在tcp連接中 難免會(huì)出現(xiàn)粘包和斷包的現(xiàn)象,這樣我們就無法獲取到正確的信息,所以在開發(fā)過程中我們要對(duì)數(shù)據(jù)粘包和斷包進(jìn)行處理,拿到我們想要的數(shù)據(jù)

數(shù)據(jù)包格式.png
示例:FC 000C 0001 112233445566 01 0010 FF 94
假如這就是我們想要拿到的正確數(shù)據(jù)
LEN0和LEN1是數(shù)據(jù)長度
首先我們要先打拿到整個(gè)數(shù)據(jù)的長度 000C是一個(gè)16進(jìn)制數(shù),轉(zhuǎn)換成十進(jìn)制就是12。
這里的12指的是數(shù)據(jù)本身的長度,不是轉(zhuǎn)換成字符串的長度,字符串的長度是24。
所以內(nèi)容數(shù)據(jù)就是 0001 112233445566 01 0010 FF
最后的94是校驗(yàn)碼
所以我們需要根據(jù)內(nèi)容數(shù)據(jù)的長度12去拿取正確的數(shù)據(jù)
代碼如下
//存儲(chǔ)TCP連接接收的數(shù)據(jù) 用于解決粘包、斷包問題
@property (strong, nonatomic) NSMutableData *readBuf;
在接收到數(shù)據(jù)方法里進(jìn)行處理
FC 000C 0001 112233445566 01 0010 FF 94
//處理粘包與斷包
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
_readBuf = [NSMutableData dataWithData:data];
// NSLog(@"直接得到的數(shù)據(jù)%@",_readBuf);
while (_readBuf.length >= 3) {
//長度數(shù)據(jù) 000C
NSData *lengthData = [_readBuf subdataWithRange:NSMakeRange(1, 2)];
//內(nèi)容長度 12
NSInteger length = [[self toHexstring:[self dataToString:lengthData]] integerValue];
//一個(gè)包的完整長度 加上開頭的FC000C和最后的校驗(yàn)碼94
NSInteger complateDataLength = length + 4;
if (_readBuf.length >= complateDataLength) {//夠一個(gè)整包長度
//截取一個(gè)包的長度(解決粘包)
NSData *complateData = [_readBuf subdataWithRange:NSMakeRange(0, complateDataLength)];
//處理數(shù)據(jù)
[self handleTcpResponseData:complateData];
//從緩存中截掉處理完的數(shù)據(jù),繼續(xù)循環(huán)
_readBuf = [NSMutableData dataWithData:[_readBuf subdataWithRange:NSMakeRange(complateDataLength, _readBuf.length - complateDataLength)]];
} else {//如果緩存中的數(shù)據(jù)長度不夠一個(gè)包的長度,則包不完整(處理半包,繼續(xù)讀取)
[sock readDataWithTimeout:-1 buffer:_readBuf bufferOffset:_readBuf.length tag:0];//繼續(xù)讀取數(shù)據(jù)
return;
}
//緩存中數(shù)據(jù)都處理完了,繼續(xù)讀取新數(shù)據(jù)
[sock readDataWithTimeout:-1 buffer:_readBuf bufferOffset:_readBuf.length tag:0];//繼續(xù)讀取數(shù)據(jù)
}
}
handleTcpResponseData方法是自己寫的處理數(shù)據(jù)方法。