1 客户端与服务端的连接规则
一般客户端与服务端要实现TCP连接,要遵循一定的规则:比如【header字节数组 + Body字节数组 】组成要发送的数据。
其中header数组一般由服务端和客户端的传输协议,用来进行数据的解析。比如下面的header传输协议
下面是传输数据封包代码:
static uint const kSocketVersion = 1; //当前Socket版本
static uint const kSocketFlag = 1;
static int const kHeaderLength = 36;//sokect头部预留长度
-(void)sendDataWithMainType:(ushort)mainType subType:(ushort)subType andBody:(NSString *)body {
/** 后台约定的编码格式 */
NSStringEncoding GBKEncoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSData *bodyData = [body dataUsingEncoding:GBKEncoding];
NSString *lenght = [NSString stringWithFormat:@"%ld",bodyData.length];
int num = [lenght intValue];
Byte buffData[20];
/** 数据拼接 */
NSMutableData *totalData = [[NSMutableData alloc] init];
NSData *bodyLenghtData = [NSData dataWithBytes:&num length:4];//消息体长度字节数组数据
NSData *mtypeData = [NSData dataWithBytes:&mainType length:2];//主类型字节数组数据
NSData *stypeData = [NSData dataWithBytes:&subType length:2];//子类型字节数组数据
NSData *version = [NSData dataWithBytes:&kSocketVersion length:4];//版本
NSData *flag = [NSData dataWithBytes:&kSocketFlag length:4];//标识
NSData *bufferData = [NSData dataWithBytes:buffData length:20];//预留
[totalData appendData:bodyLenghtData];
[totalData appendData:mtypeData];
[totalData appendData:stypeData];
[totalData appendData:version];
[totalData appendData:flag];
[totalData appendData:bufferData];
[totalData appendData:bodyData];
[self.socket writeData:totalData withTimeout:-1 tag:kTag];
}
2.Socket数据的接收
接收到服务端返回的数据后,除了需要拆包提取出包里面的数据外,由于数据包大小的问题,还有可能出现半包、粘包等问题。下面是接收数据后的处理代码:
//接收信息
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
[self.completeData appendData:data];
/** 递归方式读取返回的数据 先判断返回数据是否大于头部长度,如果没有直接加入缓存 */
while (self.completeData.length >= kHeaderLength) {
/** 拆包 */
NSData *header = [self.completeData subdataWithRange:NSMakeRange(0, 36)];
NSData *bodyLengthData = [header subdataWithRange:NSMakeRange(0, 4)];
NSData *mainTypeData = [header subdataWithRange:NSMakeRange(4, 2)];
NSData *subTypeData = [header subdataWithRange:NSMakeRange(6,2)];
[mainTypeData getBytes:&_curMainType length:2];
[subTypeData getBytes:&_curSubType length:2];
[bodyLengthData getBytes:&_curBodyDataLength length:4];
NSInteger completeDataLength = _curBodyDataLength + kHeaderLength;//完整包长度(内容长度+头长度)
/** 判断是否是够完整包 */
if (self.completeData.length >= completeDataLength)
{
NSData *curData = [self.completeData subdataWithRange:NSMakeRange(0, completeDataLength)];//截取一个包的长度(处理粘包)
[self handleSocketResponseData:curData];//处理包数据
self.completeData = [NSMutableData dataWithData:[self.completeData subdataWithRange:NSMakeRange(completeDataLength, self.completeData.length - completeDataLength)]];
}else
{
[_socket readDataWithTimeout:-1 buffer:self.completeData bufferOffset:self.completeData.length tag:0];//继续读取数据
return;
}
}
[_socket readDataWithTimeout:-1 buffer:self.completeData bufferOffset:self.completeData.length tag:0];//继续读取数据
}
-(void)handleSocketResponseData:(NSData *)data{
NSData *bodyData = [data subdataWithRange:NSMakeRange(36, [data length] -kHeaderLength)];
NSString *msg = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding];
if (_curSubType != kSOCKETMSGTYPE_HEARTBEAT && ![[NSString replaceNullValue:msg] isEqualToString:@""]) {
DDLogDebug(@"\n接收到的消息体 = %@\n接收到的主类型 = %d\n接收的子类型 = %d\n",msg,_curMainType,_curSubType);
IDSocketRequestInfo *requestInfo = [[IDSocketRequestInfo alloc] init];
requestInfo.requestBody = msg;
requestInfo.requestMainType = _curMainType;
requestInfo.requestSubType = _curSubType;
[[NSNotificationCenter defaultCenter] postNotificationName:kSocketDidRecivedDataNotification object:requestInfo userInfo:nil];
}
}
希望文章对有用Socket网络协议进行网络数据传输的同学有帮助,谢谢阅读。