使用socket(AsyncSocket、GCDAsyncSocket)进行文件的断点上传操作
来源:互联网 发布:艳子钩把淘宝店 编辑:程序博客网 时间:2024/06/09 17:55
https://github.com/potato512/SYDemo_SYSocket
通常使用网络进行文件的断点续传时,都是文件的断点下载,很少有文件的断点上传的例子。现在通过socket方式做了一个文件的断点上传。socket使用了AsyncSocket,或是GCDAsyncSocket。
AsyncSocket:http://code.google.com/p/cocoaasyncsocket/
GCDAsyncSocket:https://github.com/robbiehanson/CocoaAsyncSocket
在使用时,先将socket进行了封装。然后再使用封装类。
封装类文件
// .h文件//// SocketManager.h// zhangshaoyu//// Created by zhangshaoyu on 15/9/22.// Copyright (c) 2015年 zhangshaoyu. All rights reserved.// socket断点上传文件#import <Foundation/Foundation.h>/// 掉线类型(服务端掉线,或用户主动退出)typedef NS_ENUM(NSInteger, SocketDisconnectType){ /// 服务器掉线,默认为0 SocketOfflineByServer = 0, /// 用户主动cut SocketOfflineByUser = 1};@interface SocketManager : NSObject/// 掉线类型@property (nonatomic, assign) SocketDisconnectType disconnecType;/// 文件路径@property (nonatomic, copy) NSString *filePath;/// 单例+ (SocketManager *)sharedSocket;/// socket连接- (void)socketConnectWithHost:(NSString *)host port:(UInt16)port;/// socket连接断开- (void)socketDisconnect;/// GCDSocket连接- (void)GCDSocketConnectWithHost:(NSString *)host port:(UInt16)port;;/// GCDSocket连接断开- (void)GCDSocketDisconnect;@end
// .m文件//// SocketManager.m// zhangshaoyu//// Created by zhangshaoyu on 15/9/22.// Copyright (c) 2015年 zhangshaoyu. All rights reserved.//#import "SocketManager.h"#import "AsyncSocket.h"#import "GCDAsyncSocket.h"unsigned long long OffSet = 1024 * 200;static NSInteger const timeWithout = -1;static NSInteger const tagWriteData = 1;static NSInteger const tagReadData = 2;static NSString *const keyOffset = @"keyOffset";static NSString *const keySouceId = @"keySouceId";@interface SocketManager () <AsyncSocketDelegate, GCDAsyncSocketDelegate>@property (nonatomic, strong) GCDAsyncSocket *GCDSocket;@property (nonatomic, strong) AsyncSocket *socket; // socket@property (nonatomic, copy) NSString *socketHost; // socket的Host@property (nonatomic, assign) UInt16 socketPort; // socket的prot@property (nonatomic, strong) NSTimer *socketTimer; // 计时器@property (nonatomic, assign) BOOL isUploadHead; // 文件上传头文件协议@property (nonatomic, assign) unsigned long long filelength; // 文件上传大小@property (nonatomic, strong) NSString *fileName; // 文件上传名称@property (nonatomic, strong) NSString *fileSouceId; // 文件上传id@property (nonatomic, strong) NSFileHandle *fileHandle; // 文件操作@property (nonatomic, assign) unsigned long long currentOffset; // 当前累计读取文件大小@end@implementation SocketManager/// 单例+ (SocketManager *)sharedSocket{ static SocketManager *sharedInstace = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstace = [[self alloc] init]; }); return sharedInstace;}#pragma mark - setter- (void)setDisconnecType:(SocketDisconnectType)disconnecType{ _disconnecType = disconnecType; self.socket.userData = _disconnecType;}#pragma mark - asyncSocket连接掉线操作// socket连接- (void)socketConnectWithHost:(NSString *)host port:(UInt16)port{ if (!host || 0 >= host.length) { return; } self.socketHost = host; self.socketPort = port; // 在连接前先进行手动断开 self.disconnecType = SocketOfflineByUser; [self socketDisconnect]; // 确保断开后再连,如果对一个正处于连接状态的socket进行连接,会出现崩溃 self.disconnecType = SocketOfflineByServer; [self socketConnect];}// 连接- (void)socketConnect{ /* dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 处理耗时操作的代码块... self.isUploadHead = YES; // NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:keyOffset];// self.currentOffset = number.longLongValue; self.currentOffset = 0; self.socket = [[AsyncSocket alloc] initWithDelegate:self]; NSError *error = nil; [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:3 error:&error]; // //通知主线程刷新// dispatch_async(dispatch_get_main_queue(), ^{// //回调或者说是通知主线程刷新, // }); }); */ self.isUploadHead = YES; NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:keyOffset]; self.currentOffset = number.longLongValue;// self.currentOffset = 0; self.socket = [[AsyncSocket alloc] initWithDelegate:self]; NSError *error = nil; [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:timeWithout error:&error];}// socket断开连接- (void)socketDisconnect{ [self stopTimer:NO];}#pragma mark - AsyncSocketDelegate// 连接成功回调- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"socket连接成功"); // // 获取服务端返回数据// [self.socket readDataWithTimeout:timeWithout tag:tagReadData]; // 每隔30s像服务器发送心跳包 // 在longConnectToSocket方法中进行长连接需要向服务器发送的讯息 [self startTimer:NO];}// 重连- (void)onSocketDidDisconnect:(AsyncSocket *)sock{ NSLog(@"sorry the connect is failure %ld",sock.userData); if (SocketOfflineByServer == self.socket.userData) { // 服务器掉线,重连 [self socketConnect]; } else if (SocketOfflineByUser == self.socket.userData) { // 如果由用户断开,不进行重连 return; }}- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSLog(@"sock read"); // 对得到的data值进行解析与转换即可 [self fileInfoWithData:data]; // if (tagReadData == tag)// {// // 对得到的data值进行解析与转换即可// NSString *receiveStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];// NSLog(@"receiveStr %@", receiveStr);// NSArray *receiveArray = [receiveStr componentsSeparatedByString:@";"];// NSString *sourceid = [receiveArray firstObject];// NSRange rangeSource = [sourceid rangeOfString:@"sourceid="];// self.fileSouceId = [sourceid substringFromIndex:(rangeSource.location + rangeSource.length)];// // NSString *position = [receiveArray lastObject];// NSRange rangePosition = [position rangeOfString:@"position="];// self.currentOffset = [position substringFromIndex:(rangePosition.location + rangePosition.length)].integerValue;// // [self startTimer:NO];// }}- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"sock wirte"); if (tagWriteData == tag) { [self startTimer:NO]; }}#pragma mark - timer- (void)startTimer:(BOOL)isGCD{ [self uploadFileData:isGCD];}- (void)stopTimer:(BOOL)isGCD{ if (self.fileHandle) { [self.fileHandle closeFile]; self.fileHandle = nil; } if (isGCD) { if (self.GCDSocket) { if ([self.GCDSocket isConnected]) { [self.GCDSocket disconnect]; } self.GCDSocket.delegate = nil; self.GCDSocket = nil; } } else { // 声明是由用户主动切断 self.socket.userData = SocketOfflineByUser; if (self.socket) { if ([self.socket isConnected]) { [self.socket disconnect]; } self.socket.delegate = nil; self.socket = nil; } } self.isUploadHead = NO; NSNumber *number = [NSNumber numberWithLongLong:self.currentOffset]; [[NSUserDefaults standardUserDefaults] setObject:number forKey:keyOffset]; [[NSUserDefaults standardUserDefaults] synchronize];}#pragma mark - 信息处理// 文件长度,即大小- (unsigned long long)filelength{ if (!_filelength) { NSData *fileData = [[NSData alloc] initWithContentsOfFile:self.filePath]; _filelength = fileData.length; NSLog(@"fileData length %llu", _filelength); return _filelength; } return _filelength;}// 文件名称- (NSString *)fileName{ if (!_fileName) { NSRange fileRange = [self.filePath rangeOfString:@"/" options:NSBackwardsSearch]; if (fileRange.location != NSNotFound) { _fileName = [self.filePath substringFromIndex:(fileRange.location + fileRange.length)]; NSLog(@"filename %@", _fileName); } return _fileName; } return _fileName;}// 对得到的data值进行解析与转换即可- (void)fileInfoWithData:(NSData *)data{ // 对得到的data值进行解析与转换即可 NSString *receiveStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"receiveStr %@", receiveStr); NSArray *receiveArray = [receiveStr componentsSeparatedByString:@";"]; NSString *sourceid = [receiveArray firstObject]; NSRange rangeSource = [sourceid rangeOfString:@"sourceid="]; self.fileSouceId = [sourceid substringFromIndex:(rangeSource.location + rangeSource.length)]; [[NSUserDefaults standardUserDefaults] setObject:self.fileSouceId forKey:keySouceId]; [[NSUserDefaults standardUserDefaults] synchronize]; NSString *position = [receiveArray lastObject]; NSRange rangePosition = [position rangeOfString:@"position="]; self.currentOffset = [position substringFromIndex:(rangePosition.location + rangePosition.length)].integerValue;}// 上传文件- (void)uploadFileData:(BOOL)isGCD{ if (self.isUploadHead) { // 判断文件是否已有上传记录 self.fileSouceId = [[NSUserDefaults standardUserDefaults] objectForKey:keySouceId]; // 构造拼接协议 NSString *headStr = [[NSString alloc] initWithFormat:@"Content-Length=%llu;filename=%@;sourceid=%@\r\n", self.filelength, self.fileName, ((self.fileSouceId && 0 < self.fileSouceId.length) ? self.fileSouceId : @"")]; NSData *headData = [headStr dataUsingEncoding:NSUTF8StringEncoding]; if (isGCD) { [self.GCDSocket writeData:headData withTimeout:timeWithout tag:tagWriteData]; // 获取服务端返回数据 [self.GCDSocket readDataWithTimeout:timeWithout tag:tagReadData]; } else { [self.socket writeData:headData withTimeout:timeWithout tag:tagWriteData]; // 获取服务端返回数据 [self.socket readDataWithTimeout:timeWithout tag:tagReadData]; } headData = nil; self.isUploadHead = NO; } else { if (!self.fileHandle) { self.fileHandle = [NSFileHandle fileHandleForReadingAtPath:self.filePath]; } if (self.fileHandle) { // 文件当前上传记录位置,及是否继续上传 if (self.filelength > self.currentOffset) { NSLog(@"currentOffset %llu", self.currentOffset); [self.fileHandle seekToFileOffset:self.currentOffset]; self.currentOffset += OffSet; NSData *bodyData = [self.fileHandle readDataOfLength:self.currentOffset]; if (isGCD) { [self.GCDSocket writeData:bodyData withTimeout:timeWithout tag:tagWriteData]; } else { [self.socket writeData:bodyData withTimeout:timeWithout tag:tagWriteData]; } bodyData = nil; } else { // 停止上传,即上传完成 [self stopTimer:isGCD]; } } }}#pragma mark - gcdasyncSocket连接掉线操作- (void)GCDSocketConnectWithHost:(NSString *)host port:(UInt16)port;{ if (!host || 0 >= host.length) { return; } self.socketHost = host; self.socketPort = port; self.isUploadHead = YES; NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:keyOffset]; self.currentOffset = number.longLongValue;// self.currentOffset = 0; // Create our GCDAsyncSocket instance. // dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) dispatch_get_main_queue() self.GCDSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; // Now we tell the ASYNCHRONOUS socket to connect. NSError *error = nil; if (![self.GCDSocket connectToHost:self.socketHost onPort:self.socketPort error:&error]) { NSLog(@"Unable to connect to due to invalid configuration: %@", error); } else { NSLog(@"Connecting to \"%@\" on port %hu...", self.socketHost, self.socketPort); }}- (void)GCDSocketDisconnect{ [self stopTimer:YES];}#pragma mark GCDAsyncSocketDelegate- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{ // Since we requested HTTP/1.0, we expect the server to close the connection as soon as it has sent the response. NSLog(@"6 socketDidDisconnect:%@", err); [self GCDSocketDisconnect];}- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"1 didConnectToHost:%@ port:%hu", host, port); [self startTimer:YES];}- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler{ NSLog(@"2 didReceiveTrust:");}- (void)socketDidSecure:(GCDAsyncSocket *)sock{ // This method will be called if USE_SECURE_CONNECTION is set NSLog(@"3 socketDidSecure:");}- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"4 didWriteDataWithTag:"); if (tagWriteData == tag) { [self startTimer:YES]; }}- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSLog(@"5 didReadData:"); if (tagReadData == tag) { // 对得到的data值进行解析与转换即可 [self fileInfoWithData:data]; }}@end
使用
// 1 导入头文件#import "SocketManager.h"
// 2 启动socket连接- (void)socketStart:(UIButton *)button{ // 设置IP地址 NSString *host = @"192.168.54.160"; // @"192.186.100.21"; // kTestHost // 设置端口 UInt16 port = 7876; // 10045; // 23 // 设置文件路径 NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"text" ofType:@"txt"];// NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"dawan" ofType:@"mp4"];// NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"hongri" ofType:@"mp3"]; // 设置socket要上传的文件路径 [SocketManager sharedSocket].filePath = filePaht; // 启动socket连接// [[SocketManager sharedSocket] socketConnectWithHost:host port:port]; [[SocketManager sharedSocket] GCDSocketConnectWithHost:host port:port];}
// 3 关闭socket连接- (void)socketStop:(UIButton *)button{ // 关闭socket连接// [[SocketManager sharedSocket] socketDisconnect]; [[SocketManager sharedSocket] GCDSocketDisconnect];}
0 0
- 使用socket(AsyncSocket、GCDAsyncSocket)进行文件的断点上传操作
- 使用socket(AsyncSocket、GCDAsyncSocket)进行文件的断点上传操作
- 使用Socket进行大文件断点上传续传
- Android学习笔记(十三)-使用Socket进行大文件断点上传续传
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- iOS socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- Android应用开发之使用Socket进行大文件断点上传续传
- Android应用开发之使用Socket进行大文件断点上传续传
- Android应用开发之使用Socket进行大文件断点上传续传
- Android应用开发之使用Socket进行大文件断点上传续传
- Android通知Notification全面剖析
- GitHub学习笔记 --- .gitignore配置说明
- 程序员,你为什么值这么多钱?
- iOS开发微信支付图文教程
- 关于XML Schema命名空间中已经有xmlns却还要targetnamespace的理解
- 使用socket(AsyncSocket、GCDAsyncSocket)进行文件的断点上传操作
- ESXi主机证书替换
- 安卓发送邮件————(非启动第三方app)
- c++ this指针的用法
- Centos7 ZABBIX3.0安装
- 【第十四周项目2 - 二叉树排序树中查找的路径】
- 尝试新思路——CError和CExit
- 前端总结:踩过的坑以及一些冷知识
- Grunt使用学习入门