使用socket(AsyncSocket、GCDAsyncSocket)进行文件的断点上传操作


转自:http://blog.csdn.net/potato512/article/details/53432559

关于分包:http://ios.jobbole.com/92889/?from=singlemessage&isappinstalled=0


https://github.com/potato512/SYDemo_SYSocket

通常使用网络进行文件的断点续传时,都是文件的断点下载,很少有文件的断点上传的例子。现在通过socket方式做了一个文件的断点上传。socket使用了AsyncSocket,或是GCDAsyncSocket。

AsyncSocket:http://code.google.com/p/cocoaasyncsocket/

GCDAsyncSocket:https://github.com/robbiehanson/CocoaAsyncSocket

在使用时,先将socket进行了封装。然后再使用封装类。

封装类文件

[html]  view plain  copy
  1. // .h文件  
  2. //  
  3. //  SocketManager.h  
  4. //  zhangshaoyu  
  5. //  
  6. //  Created by zhangshaoyu on 15/9/22.  
  7. //  Copyright (c) 2015年 zhangshaoyu. All rights reserved.  
  8. //  socket断点上传文件  
  9.   
  10. #import <Foundation/Foundation.h>  
  11.   
  12. /// 掉线类型(服务端掉线,或用户主动退出)  
  13. typedef NS_ENUM(NSInteger, SocketDisconnectType)  
  14. {  
  15.     /// 服务器掉线,默认为0  
  16.     SocketOfflineByServer = 0,  
  17.       
  18.     /// 用户主动cut  
  19.     SocketOfflineByUser = 1  
  20. };  
  21.   
  22. @interface SocketManager : NSObject  
  23.   
  24. /// 掉线类型  
  25. @property (nonatomic, assign) SocketDisconnectType disconnecType;  
  26.   
  27. /// 文件路径  
  28. @property (nonatomic, copy) NSString *filePath;  
  29.   
  30. /// 单例  
  31. + (SocketManager *)sharedSocket;  
  32.   
  33. /// socket连接  
  34. - (void)socketConnectWithHost:(NSString *)host port:(UInt16)port;  
  35.   
  36. /// socket连接断开  
  37. - (void)socketDisconnect;  
  38.   
  39. /// GCDSocket连接  
  40. - (void)GCDSocketConnectWithHost:(NSString *)host port:(UInt16)port;;  
  41.   
  42. /// GCDSocket连接断开  
  43. - (void)GCDSocketDisconnect;  
  44.   
  45. @end  
[html]  view plain  copy
  1. // .m文件  
  2. //  
  3. //  SocketManager.m  
  4. //  zhangshaoyu  
  5. //  
  6. //  Created by zhangshaoyu on 15/9/22.  
  7. //  Copyright (c) 2015年 zhangshaoyu. All rights reserved.  
  8. //  
  9.   
  10. #import "SocketManager.h"  
  11. #import "AsyncSocket.h"  
  12. #import "GCDAsyncSocket.h"  
  13.   
  14. unsigned long long OffSet = 1024 * 200;  
  15.   
  16. static NSInteger const timeWithout = -1;  
  17. static NSInteger const tagWriteData = 1;  
  18. static NSInteger const tagReadData = 2;  
  19.   
  20. static NSString *const keyOffset = @"keyOffset";  
  21. static NSString *const keySouceId = @"keySouceId";  
  22.   
  23. @interface SocketManager () <AsyncSocketDelegate, GCDAsyncSocketDelegate>  
  24.   
  25. @property (nonatomic, strong) GCDAsyncSocket *GCDSocket;  
  26. @property (nonatomic, strong) AsyncSocket *socket;  // socket  
  27. @property (nonatomic, copy) NSString *socketHost;   // socket的Host  
  28. @property (nonatomic, assign) UInt16 socketPort;    // socket的prot  
  29. @property (nonatomic, strong) NSTimer *socketTimer; // 计时器  
  30.   
  31. @property (nonatomic, assign) BOOL isUploadHead;                // 文件上传头文件协议  
  32. @property (nonatomic, assign) unsigned long long filelength;    // 文件上传大小  
  33. @property (nonatomic, strong) NSString *fileName;               // 文件上传名称  
  34. @property (nonatomic, strong) NSString *fileSouceId;            // 文件上传id  
  35. @property (nonatomic, strong) NSFileHandle *fileHandle;         // 文件操作  
  36. @property (nonatomic, assign) unsigned long long currentOffset; // 当前累计读取文件大小  
  37.   
  38. @end  
  39.   
  40. @implementation SocketManager  
  41.   
  42. /// 单例  
  43. + (SocketManager *)sharedSocket  
  44. {  
  45.     static SocketManager *sharedInstace = nil;  
  46.     static dispatch_once_t onceToken;  
  47.     dispatch_once(&onceToken, ^{  
  48.         sharedInstace = [[self alloc] init];  
  49.     });  
  50.       
  51.     return sharedInstace;  
  52. }  
  53.   
  54. #pragma mark - setter  
  55.   
  56. - (void)setDisconnecType:(SocketDisconnectType)disconnecType  
  57. {  
  58.     _disconnecType = disconnecType;  
  59.     self.socket.userData = _disconnecType;  
  60. }  
  61.   
  62. #pragma mark - asyncSocket连接掉线操作  
  63.   
  64. // socket连接  
  65. - (void)socketConnectWithHost:(NSString *)host port:(UInt16)port  
  66. {  
  67.     if (!host || 0 >= host.length)  
  68.     {  
  69.         return;  
  70.     }  
  71.       
  72.     self.socketHost = host;  
  73.     self.socketPort = port;  
  74.       
  75.     // 在连接前先进行手动断开  
  76.     self.disconnecType = SocketOfflineByUser;  
  77.     [self socketDisconnect];  
  78.     // 确保断开后再连,如果对一个正处于连接状态的socket进行连接,会出现崩溃  
  79.     self.disconnecType = SocketOfflineByServer;  
  80.       
  81.     [self socketConnect];  
  82. }  
  83.   
  84. // 连接  
  85. - (void)socketConnect  
  86. {  
  87.     /*  
  88.     dispatch_async(dispatch_get_global_queue(0, 0), ^{  
  89.       
  90.         // 处理耗时操作的代码块...  
  91.         self.isUploadHead = YES;  
  92.           
  93. //        NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:keyOffset];  
  94. //        self.currentOffset = number.longLongValue;  
  95.         self.currentOffset = 0;  
  96.           
  97.         self.socket = [[AsyncSocket alloc] initWithDelegate:self];  
  98.         NSError *error = nil;  
  99.         [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:3 error:&error];  
  100.           
  101. //        //通知主线程刷新  
  102. //        dispatch_async(dispatch_get_main_queue(), ^{  
  103. //            //回调或者说是通知主线程刷新,   
  104. //        });  
  105.     });  
  106.     */  
  107.       
  108.     self.isUploadHead = YES;  
  109.       
  110.     NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:keyOffset];  
  111.     self.currentOffset = number.longLongValue;  
  112. //    self.currentOffset = 0;  
  113.       
  114.     self.socket = [[AsyncSocket alloc] initWithDelegate:self];  
  115.     NSError *error = nil;  
  116.     [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:timeWithout error:&error];  
  117. }  
  118.   
  119. // socket断开连接  
  120. - (void)socketDisconnect  
  121. {  
  122.     [self stopTimer:NO];  
  123. }  
  124.   
  125. #pragma mark - AsyncSocketDelegate  
  126.   
  127. // 连接成功回调  
  128. - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port  
  129. {  
  130.     NSLog(@"socket连接成功");  
  131.       
  132. //    // 获取服务端返回数据  
  133. //    [self.socket readDataWithTimeout:timeWithout tag:tagReadData];  
  134.       
  135.     // 每隔30s像服务器发送心跳包  
  136.     // 在longConnectToSocket方法中进行长连接需要向服务器发送的讯息  
  137.     [self startTimer:NO];  
  138. }  
  139.   
  140. // 重连  
  141. - (void)onSocketDidDisconnect:(AsyncSocket *)sock  
  142. {  
  143.     NSLog(@"sorry the connect is failure %ld",sock.userData);  
  144.     if (SocketOfflineByServer == self.socket.userData)  
  145.     {  
  146.         // 服务器掉线,重连  
  147.         [self socketConnect];  
  148.     }  
  149.     else if (SocketOfflineByUser == self.socket.userData)  
  150.     {  
  151.         // 如果由用户断开,不进行重连  
  152.         return;  
  153.     }  
  154. }  
  155.   
  156. - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag  
  157. {  
  158.     NSLog(@"sock read");  
  159.       
  160.     // 对得到的data值进行解析与转换即可  
  161.     [self fileInfoWithData:data];  
  162.       
  163. //    if (tagReadData == tag)  
  164. //    {  
  165. //        // 对得到的data值进行解析与转换即可  
  166. //        NSString *receiveStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
  167. //        NSLog(@"receiveStr %@", receiveStr);  
  168. //        NSArray *receiveArray = [receiveStr componentsSeparatedByString:@";"];  
  169. //        NSString *sourceid = [receiveArray firstObject];  
  170. //        NSRange rangeSource = [sourceid rangeOfString:@"sourceid="];  
  171. //        self.fileSouceId = [sourceid substringFromIndex:(rangeSource.location + rangeSource.length)];  
  172. //          
  173. //        NSString *position = [receiveArray lastObject];  
  174. //        NSRange rangePosition = [position rangeOfString:@"position="];  
  175. //        self.currentOffset = [position substringFromIndex:(rangePosition.location + rangePosition.length)].integerValue;  
  176. //          
  177. //        [self startTimer:NO];  
  178. //    }  
  179. }  
  180.   
  181. - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag  
  182. {  
  183.     NSLog(@"sock wirte");  
  184.       
  185.     if (tagWriteData == tag)  
  186.     {  
  187.         [self startTimer:NO];  
  188.     }  
  189. }  
  190.   
  191. #pragma mark - timer  
  192.   
  193. - (void)startTimer:(BOOL)isGCD  
  194. {  
  195.     [self uploadFileData:isGCD];  
  196. }  
  197.   
  198. - (void)stopTimer:(BOOL)isGCD  
  199. {  
  200.     if (self.fileHandle)  
  201.     {  
  202.         [self.fileHandle closeFile];  
  203.         self.fileHandle = nil;  
  204.     }  
  205.       
  206.     if (isGCD)  
  207.     {  
  208.         if (self.GCDSocket)  
  209.         {  
  210.             if ([self.GCDSocket isConnected])  
  211.             {  
  212.                 [self.GCDSocket disconnect];  
  213.             }  
  214.             self.GCDSocket.delegate = nil;  
  215.             self.GCDSocket = nil;  
  216.         }  
  217.     }  
  218.     else  
  219.     {  
  220.         // 声明是由用户主动切断  
  221.         self.socket.userData = SocketOfflineByUser;  
  222.           
  223.         if (self.socket)  
  224.         {  
  225.             if ([self.socket isConnected])  
  226.             {  
  227.                 [self.socket disconnect];  
  228.             }  
  229.             self.socket.delegate = nil;  
  230.             self.socket = nil;  
  231.         }  
  232.     }  
  233.       
  234.     self.isUploadHead = NO;  
  235.       
  236.     NSNumber *number = [NSNumber numberWithLongLong:self.currentOffset];  
  237.     [[NSUserDefaults standardUserDefaults] setObject:number forKey:keyOffset];  
  238.     [[NSUserDefaults standardUserDefaults] synchronize];  
  239. }  
  240.   
  241. #pragma mark - 信息处理  
  242.   
  243. // 文件长度,即大小  
  244. - (unsigned long long)filelength  
  245. {  
  246.     if (!_filelength)  
  247.     {  
  248.         NSData *fileData = [[NSData alloc] initWithContentsOfFile:self.filePath];  
  249.         _filelength = fileData.length;  
  250.         NSLog(@"fileData length %llu", _filelength);  
  251.           
  252.         return _filelength;  
  253.     }  
  254.       
  255.     return _filelength;  
  256. }  
  257.   
  258. // 文件名称  
  259. - (NSString *)fileName  
  260. {  
  261.     if (!_fileName)  
  262.     {  
  263.         NSRange fileRange = [self.filePath rangeOfString:@"/" options:NSBackwardsSearch];  
  264.         if (fileRange.location != NSNotFound)  
  265.         {  
  266.             _fileName = [self.filePath substringFromIndex:(fileRange.location + fileRange.length)];  
  267.             NSLog(@"filename %@", _fileName);  
  268.         }  
  269.           
  270.         return _fileName;  
  271.     }  
  272.       
  273.     return _fileName;  
  274. }  
  275.   
  276. // 对得到的data值进行解析与转换即可  
  277. - (void)fileInfoWithData:(NSData *)data  
  278. {  
  279.     // 对得到的data值进行解析与转换即可  
  280.     NSString *receiveStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
  281.     NSLog(@"receiveStr %@", receiveStr);  
  282.     NSArray *receiveArray = [receiveStr componentsSeparatedByString:@";"];  
  283.     NSString *sourceid = [receiveArray firstObject];  
  284.     NSRange rangeSource = [sourceid rangeOfString:@"sourceid="];  
  285.     self.fileSouceId = [sourceid substringFromIndex:(rangeSource.location + rangeSource.length)];  
  286.     [[NSUserDefaults standardUserDefaults] setObject:self.fileSouceId forKey:keySouceId];  
  287.     [[NSUserDefaults standardUserDefaults] synchronize];  
  288.       
  289.     NSString *position = [receiveArray lastObject];  
  290.     NSRange rangePosition = [position rangeOfString:@"position="];  
  291.     self.currentOffset = [position substringFromIndex:(rangePosition.location + rangePosition.length)].integerValue;  
  292. }  
  293.   
  294. // 上传文件  
  295. - (void)uploadFileData:(BOOL)isGCD  
  296. {  
  297.     if (self.isUploadHead)  
  298.     {  
  299.         // 判断文件是否已有上传记录  
  300.         self.fileSouceId = [[NSUserDefaults standardUserDefaults] objectForKey:keySouceId];  
  301.         // 构造拼接协议  
  302.         NSString *headStr = [[NSString alloc] initWithFormat:@"Content-Length=%llu;filename=%@;sourceid=%@\r\n", self.filelength, self.fileName, ((self.fileSouceId && 0 < self.fileSouceId.length) ? self.fileSouceId : @"")];  
  303.         NSData *headData = [headStr dataUsingEncoding:NSUTF8StringEncoding];  
  304.         if (isGCD)  
  305.         {  
  306.             [self.GCDSocket writeData:headData withTimeout:timeWithout tag:tagWriteData];  
  307.               
  308.             // 获取服务端返回数据  
  309.             [self.GCDSocket readDataWithTimeout:timeWithout tag:tagReadData];  
  310.         }  
  311.         else  
  312.         {  
  313.             [self.socket writeData:headData withTimeout:timeWithout tag:tagWriteData];  
  314.               
  315.             // 获取服务端返回数据  
  316.             [self.socket readDataWithTimeout:timeWithout tag:tagReadData];  
  317.         }  
  318.         headData = nil;  
  319.           
  320.         self.isUploadHead = NO;  
  321.     }  
  322.     else  
  323.     {  
  324.         if (!self.fileHandle)  
  325.         {  
  326.             self.fileHandle = [NSFileHandle fileHandleForReadingAtPath:self.filePath];  
  327.         }  
  328.           
  329.         if (self.fileHandle)  
  330.         {  
  331.             // 文件当前上传记录位置,及是否继续上传  
  332.             if (self.filelength > self.currentOffset)  
  333.             {  
  334.                 NSLog(@"currentOffset %llu", self.currentOffset);  
  335.                   
  336.                 [self.fileHandle seekToFileOffset:self.currentOffset];  
  337.                 self.currentOffset += OffSet;  
  338.                 NSData *bodyData = [self.fileHandle readDataOfLength:self.currentOffset];  
  339.                 if (isGCD)  
  340.                 {  
  341.                     [self.GCDSocket writeData:bodyData withTimeout:timeWithout tag:tagWriteData];  
  342.                 }  
  343.                 else  
  344.                 {  
  345.                     [self.socket writeData:bodyData withTimeout:timeWithout tag:tagWriteData];  
  346.                 }  
  347.   
  348.                 bodyData = nil;  
  349.             }  
  350.             else  
  351.             {  
  352.                 // 停止上传,即上传完成  
  353.                 [self stopTimer:isGCD];  
  354.             }  
  355.         }  
  356.     }  
  357. }  
  358.   
  359. #pragma mark - gcdasyncSocket连接掉线操作  
  360.   
  361. - (void)GCDSocketConnectWithHost:(NSString *)host port:(UInt16)port;  
  362. {  
  363.     if (!host || 0 >= host.length)  
  364.     {  
  365.         return;  
  366.     }  
  367.       
  368.     self.socketHost = host;  
  369.     self.socketPort = port;  
  370.       
  371.     self.isUploadHead = YES;  
  372.       
  373.     NSNumber *number = [[NSUserDefaults standardUserDefaults] objectForKey:keyOffset];  
  374.     self.currentOffset = number.longLongValue;  
  375. //    self.currentOffset = 0;  
  376.       
  377.     // Create our GCDAsyncSocket instance.  
  378.     // dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) dispatch_get_main_queue()  
  379.     self.GCDSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];  
  380.       
  381.     // Now we tell the ASYNCHRONOUS socket to connect.  
  382.     NSError *error = nil;  
  383.     if (![self.GCDSocket connectToHost:self.socketHost onPort:self.socketPort error:&error])  
  384.     {  
  385.         NSLog(@"Unable to connect to due to invalid configuration: %@", error);  
  386.     }  
  387.     else  
  388.     {  
  389.         NSLog(@"Connecting to \"%@\" on port %hu...", self.socketHost, self.socketPort);  
  390.     }  
  391. }  
  392.   
  393. - (void)GCDSocketDisconnect  
  394. {  
  395.     [self stopTimer:YES];  
  396. }  
  397.   
  398. #pragma mark GCDAsyncSocketDelegate  
  399.   
  400. - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err  
  401. {  
  402.     // Since we requested HTTP/1.0, we expect the server to close the connection as soon as it has sent the response.  
  403.     NSLog(@"6 socketDidDisconnect:%@", err);  
  404.       
  405.     [self GCDSocketDisconnect];  
  406. }  
  407.   
  408. - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port  
  409. {  
  410.     NSLog(@"1 didConnectToHost:%@ port:%hu", host, port);  
  411.   
  412.     [self startTimer:YES];  
  413. }  
  414.   
  415. - (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler  
  416. {  
  417.     NSLog(@"2 didReceiveTrust:");  
  418. }  
  419.   
  420. - (void)socketDidSecure:(GCDAsyncSocket *)sock  
  421. {  
  422.     // This method will be called if USE_SECURE_CONNECTION is set  
  423.     NSLog(@"3 socketDidSecure:");  
  424. }  
  425.   
  426. - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag  
  427. {  
  428.     NSLog(@"4 didWriteDataWithTag:");  
  429.       
  430.     if (tagWriteData == tag)  
  431.     {  
  432.         [self startTimer:YES];  
  433.     }  
  434. }  
  435.   
  436. - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag  
  437. {  
  438.     NSLog(@"5 didReadData:");  
  439.   
  440.     if (tagReadData == tag)  
  441.     {  
  442.         // 对得到的data值进行解析与转换即可  
  443.         [self fileInfoWithData:data];  
  444.     }  
  445. }  
  446.   
  447. @end  

使用

[html]  view plain  copy
  1. // 1 导入头文件  
  2. #import "SocketManager.h"  
[html]  view plain  copy
  1. // 2 启动socket连接  
  2. - (void)socketStart:(UIButton *)button  
  3. {  
  4.     // 设置IP地址  
  5.     NSString *host = @"192.168.54.160"; // @"192.186.100.21"; // kTestHost  
  6.     // 设置端口  
  7.     UInt16 port = 7876; // 10045; // 23  
  8.     // 设置文件路径  
  9.     NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"text" ofType:@"txt"];  
  10. //    NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"dawan" ofType:@"mp4"];  
  11. //    NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"hongri" ofType:@"mp3"];  
  12.     // 设置socket要上传的文件路径  
  13.     [SocketManager sharedSocket].filePath = filePaht;  
  14.     // 启动socket连接  
  15. //    [[SocketManager sharedSocket] socketConnectWithHost:host port:port];  
  16.     [[SocketManager sharedSocket] GCDSocketConnectWithHost:host port:port];  
  17. }  
[html]  view plain  copy
  1. // 3 关闭socket连接  
  2. - (void)socketStop:(UIButton *)button  
  3. {  
  4.     // 关闭socket连接  
  5. //    [[SocketManager sharedSocket] socketDisconnect];  
  6.     [[SocketManager sharedSocket] GCDSocketDisconnect];  
  7. }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值