最近做了个APP,在APP中用GCDAsyncSocket与服务器建立TCP长连接,并通过服务器控制一个设备。这个过程中,服务器会返回一些数据,有时候数据量大,接收数据时会出现断包的问题。第一次做长连接,解析数据时顾头不顾尾,只注意到本次数据的完整性,解析完后直接丢掉数据,下次的数据的包头就可能就被掐掉了,导致解析的数据长度出错,进而根据长度取数据越界而crash。
下面粘贴下自己的解决方法。
接收数据是在这个代理方法中:
- (void)socket:(GCDAsyncSocket*)sock didReadData:(NSData*)data withTag:(long)tag {
[self.receiveData appendData:data]; // receiveData是NSMutableData类型,作为一个数据缓冲池,每次从开始位置(0)取想要的数据
NSUInteger length = [self getLength:self.receiveData];// 根据你自定义的协议解析数据长度
if(self.completeData.length >= length) {
NSData*valideData = [self getValideDataWithLength:length];// 本次应该接收的数据,你可以解析它了
}
}
[self pullTheMsg];// 继续接收数据
}
// 根据长度取出本次应该接收的数据并返回,然后在缓冲数据中清除本次数据,后面的数据前移,保证每次从0位置开始取数据。
- (NSData*)getValideDataWithLength:(NSUInteger)length{
NSData*valideData = [self.receiveData subdataWithRange:NSMakeRange(0, length)];
// 余下的数据前移,一时没找到好方法,用了个笨的
NSData*lastData = [self.receiveData subdataWithRange:NSMakeRange(length,self.receiveData.length- length)];
[self clearReceiveData];
[self.receiveData appendData:lastData];
return valideData;
}
// 清空所有缓冲数据
- (void)clearReceiveData{
[self.receiveData resetBytesInRange:NSMakeRange(0, [self.receiveData length])];
[self.receiveData setLength:0];
}