WSUploadSession.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //
  2. // WSUploadloadSession.m
  3. // zhuxun
  4. //
  5. // Created by winsoft on 17/6/26.
  6. //
  7. //
  8. #import "WSUploadSession.h"
  9. #import "AsyncSocket.h"
  10. #import "DataInputStream.h"
  11. #import "DataOutputStream.h"
  12. #import "NSData+crc32.h"
  13. #import "NSData+MD5Digest.h"
  14. #import "NSDictionary+JSON.h"
  15. #import "NSString+Extension.h"
  16. #import "FileUtils.h"
  17. #define ChunkSize 8*1024
  18. @interface WSUploadSession()
  19. @property (nonatomic , copy) NSString *fileName;
  20. @property (nonatomic, copy)NSString *filePath;
  21. @property (nonatomic, copy)NSString *uuid;
  22. //@property (nonatomic, assign)AttachType attachMentType;
  23. /*文件发送相关*/
  24. @property (nonatomic, strong)AsyncSocket *asyncSocket;
  25. @property (nonatomic, strong)NSSet *runLoopModes;
  26. @property (nonatomic, copy)NSMutableData *sendData;
  27. @property (nonatomic, copy)NSString *md5;
  28. @property (nonatomic, assign)unsigned long long fileSize;
  29. //初始偏移量
  30. @property (nonatomic, assign)unsigned long long uploadOffset;
  31. @property (nonatomic , copy) NSString *host;
  32. @property (nonatomic , copy) NSString *port;
  33. @end
  34. @implementation WSUploadSession
  35. + (WSUploadSession *)uploadFileWithServerHost:(NSString *)host port:(NSString *)port fileMD5:(NSString *)fileMD5 uuid:(NSString *)uuid fileSize:(NSInteger)fileSize startSize:(NSInteger)startSize localFileFullPath:(NSString *)localFileFullPath processBlock:(UploadProgressBlock)processBlock successBlock:(UploadSuccessBlock)successBlock failBlock:(UploadFailedBlock)failBlock
  36. {
  37. WSUploadSession *uploadSession = [[WSUploadSession alloc]initUploadFileWithServerHost:host port:port fileMD5:fileMD5 uuid:uuid fileSize:fileSize startSize:startSize localFileFullPath:localFileFullPath processBlock:processBlock successBlock:successBlock failBlock:failBlock];
  38. return uploadSession;
  39. }
  40. - (id)initUploadFileWithServerHost:(NSString *)host port:(NSString *)port fileMD5:(NSString *)fileMD5 uuid:(NSString *)uuid fileSize:(NSInteger)fileSize startSize:(NSInteger)startSize localFileFullPath:(NSString *)localFileFullPath processBlock:(UploadProgressBlock)processBlock successBlock:(UploadSuccessBlock)successBlock failBlock:(UploadFailedBlock)failBlock
  41. {
  42. if (self = [super init]) {
  43. self.uploadProgressBlock = processBlock;
  44. self.uploadFailedBlock = failBlock;
  45. self.uploadSuccessBlock = successBlock;
  46. if ([_asyncSocket isConnected]) {
  47. [_asyncSocket disconnect];
  48. _asyncSocket.delegate = nil;
  49. _asyncSocket = nil;
  50. }
  51. _asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
  52. _runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
  53. _uploadOffset = startSize;
  54. if ([FileUtils fileSizeAtPath:localFileFullPath] < fileSize) {
  55. fileSize = [FileUtils fileSizeAtPath:localFileFullPath];
  56. };
  57. _fileSize = fileSize;
  58. _filePath = localFileFullPath;
  59. _fileName = localFileFullPath.lastPathComponent;
  60. _host = host;
  61. _port = port;
  62. _md5 = fileMD5;
  63. _uuid = uuid;
  64. [self operationDidStart];
  65. }
  66. return self;
  67. }
  68. //+ (void)networkRequestThreadEntryPoint:(id)__unused object {
  69. // @autoreleasepool {
  70. // [[NSThread currentThread] setName:@"TCPSocketUpLod"];
  71. // NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
  72. // [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
  73. // [runLoop run];
  74. // }
  75. //}
  76. //
  77. //+ (NSThread *)networkRequestThread {
  78. // static NSThread *_networkRequestThread = nil;
  79. // static dispatch_once_t oncePredicate;
  80. // dispatch_once(&oncePredicate, ^{
  81. // _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
  82. // [_networkRequestThread start];
  83. // });
  84. // return _networkRequestThread;
  85. //}
  86. //
  87. //
  88. //
  89. //-(void)start
  90. //{
  91. // if ([self isCancelled]) {
  92. // [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[_runLoopModes allObjects]];
  93. // } else if ([self isReady]) {
  94. // [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[_runLoopModes allObjects]];
  95. // }
  96. //}
  97. //FILE_UP_SERVER_HOST FILE_UP_SERVER_PORT
  98. - (void)operationDidStart {
  99. NSError *error;
  100. if (![_asyncSocket connectToHost:_host onPort:[_port integerValue] error:&error])
  101. {
  102. NSLog(@"Error connecting: %@", error);
  103. }
  104. }
  105. #pragma mark --
  106. #pragma mark -- sockectOperate
  107. -(void)writeToSocket:(NSMutableData *)data {
  108. [_asyncSocket writeData:data withTimeout:-1 tag:0];
  109. [_asyncSocket readDataToData:[AsyncSocket JsonData] withTimeout:-1 tag:1];
  110. }
  111. #pragma mark socket delegate
  112. - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
  113. {
  114. NSLog(@"didConnectToHost");//通过数据包的偏移位置来控制断点上传的二进制数据 00112000231
  115. NSData *bitData = [self makeChunk:_uploadOffset];
  116. if (bitData) {
  117. [self writeToSocket:[[NSMutableData alloc]initWithData:[self makeChunk:_uploadOffset]]];
  118. }
  119. }
  120. #warning 文件上传/下载只有两种状态,取消,下载
  121. -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
  122. //如果用户退出,如何判断消息是上次还是下载,则msg新增字段,这里为上传。
  123. DataInputStream *inputData = [DataInputStream dataInputStreamWithData:data];
  124. NSString *str = [inputData readUTF];
  125. if (!str) {
  126. [self cancerUpload];
  127. if (self.uploadFailedBlock) {
  128. self.uploadFailedBlock(@"error",self.uuid);
  129. }
  130. // if (self.uploadFailedDBBlock) {
  131. // self.uploadFailedDBBlock(@"error",self.uuid);
  132. // }
  133. return;
  134. }
  135. NSDictionary* dic = str.jsonValue;
  136. BOOL success = [[dic objectForKey:@"success"] boolValue];
  137. NSInteger code = [[dic valueForKey:@"code"] integerValue];
  138. if (!success) {
  139. NSString *errMessage = [dic objectForKey:@"message"];
  140. NSLog(@"message:---%@", errMessage);
  141. [self cancerUpload];
  142. if (self.uploadFailedBlock) {
  143. self.uploadFailedBlock(errMessage,self.uuid);
  144. }
  145. return;
  146. }
  147. //区分状态码的返回结果
  148. if (code == 304) {
  149. //
  150. if (self.uploadSuccessBlock) {
  151. self.uploadSuccessBlock(nil,_fileSize,self.md5);
  152. }
  153. // if (self.uploadSuccessDBBlock) {
  154. // self.uploadSuccessDBBlock(nil,_fileSize,self.md5);
  155. // }
  156. // if (self.completionBlock) {
  157. // self.completionBlock();
  158. // }
  159. //关闭连接
  160. [sock disconnect];
  161. return;
  162. }else if(code == 200){
  163. unsigned long long start = [[dic valueForKey:@"accept"] integerValue];
  164. double progress = ((double)start/_fileSize);
  165. if (self.uploadProgressBlock) {
  166. self.uploadProgressBlock(progress,start,self.uuid);
  167. NSLog(@"当前人物uuid--%@",self.uuid);
  168. }
  169. // if (self.uploadProgressDBBlock) {
  170. // self.uploadProgressDBBlock(progress,start,self.uuid);
  171. // }
  172. _uploadOffset = start;
  173. NSLog(@"已经上传%llu, 当前进度%f%%", start, progress*100);
  174. [self writeToSocket:[[NSMutableData alloc]initWithData:[self makeChunk:start]]];
  175. }
  176. }
  177. -(void)onSocketDidDisconnect:(AsyncSocket *)sock
  178. {
  179. NSLog(@"socketDidDisconnect");
  180. }
  181. -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
  182. {
  183. NSLog(@"socketDidDisconnect with error");
  184. [self cancerUpload];
  185. if (self.uploadFailedBlock) {
  186. self.uploadFailedBlock(@"onSocketDidDisconnect",self.uuid);
  187. }
  188. }
  189. #pragma mark --
  190. #pragma mark --
  191. /*客户端向服务端发送文件:
  192. 本次传输的包总长度(0-4)
  193. +协议说明JSON长度(4-8)
  194. {
  195. "md5":"E96261B90BE7B1895E9193D9CB9AAC5A",
  196. "crc":"F9C19B6F",
  197. "cmd":"1",
  198. "fileName":"0483737.xls",
  199. "offset":0,
  200. "user":
  201. {
  202. "sender":"serverid-gyj","receiver":"serverid-joe"
  203. },
  204. "fileLength":83456,
  205. "client":
  206. {
  207. "name":"realicq",
  208. "version":"6.5"
  209. },
  210. "complete":1
  211. }
  212. +文件流长度(4位)+文件流
  213. */
  214. -(NSData *)makeChunk:(unsigned long long) start{
  215. NSUInteger toSendChunkSize = 0;
  216. if (start + ChunkSize > _fileSize) {
  217. toSendChunkSize = (unsigned int)(_fileSize - start);
  218. }else{
  219. toSendChunkSize = ChunkSize;
  220. }
  221. NSData *chunk = [[NSMutableData alloc] init];
  222. if (_sendData && !_filePath) {
  223. [self cancerUpload];
  224. if (self.uploadFailedBlock) {
  225. self.uploadFailedBlock(@"upload fail",self.uuid);
  226. }
  227. return nil;
  228. }else{
  229. NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:_filePath];
  230. [readHandle seekToFileOffset:start];
  231. if(!readHandle)
  232. {
  233. [self cancerUpload];
  234. if (self.uploadFailedBlock) {
  235. self.uploadFailedBlock(@"error",self.uuid);
  236. }
  237. return nil;
  238. }
  239. NSInputStream *inputStream = [NSInputStream inputStreamWithData:[readHandle readDataOfLength:toSendChunkSize]];
  240. [inputStream open];
  241. chunk = [[NSMutableData alloc]initWithLength:toSendChunkSize];
  242. NSUInteger readLength = (NSUInteger)[inputStream read:(uint8_t*)[chunk bytes] maxLength:chunk.length];
  243. if (readLength != [chunk length]) {
  244. [self cancerUpload];
  245. if (self.uploadFailedBlock) {
  246. self.uploadFailedBlock(@"error",self.uuid);
  247. }
  248. return nil;
  249. }
  250. [inputStream close];
  251. }
  252. NSString *crc32 = [NSString stringWithFormat:@"%@",[[NSString alloc] initWithFormat:@"%08x",chunk.crc32]];
  253. NSDictionary *chunkDes = nil;
  254. // if (self.messageType == MESSAGE_TYPE_GROUP) {
  255. chunkDes = @{
  256. @"md5":_md5,
  257. @"crc":crc32,
  258. @"cmd":@"1",
  259. @"fileName":_fileName,
  260. @"offset":@(start),
  261. @"fileLength":@(_fileSize),
  262. @"client":@{@"name":@"iOS",@"version":@"1.0"},
  263. @"complete":@(1)
  264. };
  265. NSLog(@"chunkDes: %@",chunkDes);
  266. NSString *desString=[chunkDes jsonString];
  267. DataOutputStream *outData = [DataOutputStream new];
  268. [outData writeInt:0];
  269. [outData writeUTF:desString];
  270. [outData writeBytes:chunk];
  271. [outData writeDataCount];
  272. NSData *sendData = [outData toByteArray];
  273. if(!sendData)
  274. {
  275. [self cancerUpload];
  276. if (self.uploadFailedBlock) {
  277. self.uploadFailedBlock(@"error",self.uuid);
  278. }
  279. }
  280. return sendData;
  281. }
  282. - (void)cancerUpload
  283. {
  284. // [super cancel];
  285. if (_asyncSocket.isConnected) {
  286. [_asyncSocket disconnect];
  287. _asyncSocket.delegate = nil;
  288. _asyncSocket = nil;
  289. }
  290. }
  291. - (void)resumeUpload
  292. {
  293. }
  294. @end