最近在使用GCDAsyncSocket进行socket通信的工作,调试发现总是莫名的出现数据成功接收但是解析不成的情况,经分析发现一个可能性:
socket发送数据的时候会自动分包处理的,导致数据完整性验证失败。
未修复代码如下:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { ITTDINFO(@"didReadData tag %ld", tag); [_responseData appendData:data]; if ([_responseData length] > 4 && [_responseParser validateData:_responseData]) { NSData *data = [_responseData copy]; [self parseData:data]; _responseData = [NSMutableData data]; [_asyncSocket readDataWithTimeout:READ_TIME_OUT tag:READ_TAG]; } else { [_asyncSocket readDataWithTimeout:READ_TIME_OUT tag:READ_TAG]; } }
备注:
接收到的数据头4个字节表示实体数据的长度
- (BOOL)validateData:(NSData*)responseData 验证接收到数据的完整性
这样写的问题明显问题是,缓存数据_responseData中可能存在一个完整的数据包和半个数据包,这样完整性验证肯定是失败,导致解析失败
- (NSData*)hasCompleteData { NSData *completeData = nil; if ([_responseData length] > 4) { NSInteger lengthBytes = 4; NSInteger headLength = [_responseParser headLength:_responseData]; NSInteger leftLength = [_responseData length] - lengthBytes; if (leftLength >= headLength) { completeData = [_responseData subdataWithRange:NSMakeRange(0, headLength + lengthBytes)]; NSData *leftData = [_responseData subdataWithRange:NSMakeRange(headLength + lengthBytes, leftLength - headLength)]; _responseData = [[NSMutableData alloc] initWithData:leftData]; } } return completeData; } - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { ITTDINFO(@"didReadData tag %ld", tag); [_responseData appendData:data]; @synchronized(_responseData) { NSData *completeData = nil; while ((completeData = [self hasCompleteData])) { //一直从缓冲区里读获取完整的数据包,进行解析 [self parseData:data]; } [_asyncSocket readDataWithTimeout:READ_TIME_OUT tag:READ_TAG]; } }