美文网首页iOS开发IOSiOS学习开发
iOS Socket编程:传输数据的封包,接收数据后半包、粘包、

iOS Socket编程:传输数据的封包,接收数据后半包、粘包、

作者: DevinWu | 来源:发表于2017-12-01 13:43 被阅读218次

1 客户端与服务端的连接规则

一般客户端与服务端要实现TCP连接,要遵循一定的规则:比如【header字节数组 + Body字节数组 】组成要发送的数据。

其中header数组一般由服务端和客户端的传输协议,用来进行数据的解析。比如下面的header传输协议


图片.png

下面是传输数据封包代码:

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网络协议进行网络数据传输的同学有帮助,谢谢阅读。

相关文章

  • iOS Socket编程:传输数据的封包,接收数据后半包、粘包、

    1 客户端与服务端的连接规则 一般客户端与服务端要实现TCP连接,要遵循一定的规则:比如【header字节数组 +...

  • ios开发中的包的处理

    IOS 详解socket编程[oc]粘包、半包处理 在做socket编程时,如果是做tcp连接,那就不可避免的会遇...

  • 即时通讯

    iOS即时通讯,从入门到“放弃”?socket的半包,粘包与分包的问题iOS 处理socket粘包问题iOS___...

  • 关于Socket 中粘包的处理

    粘包:指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。出现粘包...

  • netty的编解码

    什么是拆包/粘包 TCP 粘包/拆包 半包:读取的数据不是一个数据包粘包:读取的数据超过一个数据包 粘包问题的解决...

  • TCP 半包粘包问题

    什么是粘包现象 TCP 粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着...

  • iOS客户端与java后台 socket通信

    1. socket需要解决粘包和分包问题 1.1什么是分包? socket一次性传输的数据大小是有限制的,当有数据...

  • TCP粘包现象

    什么是粘包现象 TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前...

  • 文章收藏

    iOS native 加载 H5 图片(沙盒加载html图片) socket的半包,粘包与分包的问题 Scoket...

  • 即时通讯下数据粘包、断包处理实例(基于CocoaAsyncSoc

    使用CocoaAsyncSocket这个框架进行数据封包和拆包。来解决频繁的数据发送下,导致的数据粘包、以及较大数...

网友评论

    本文标题:iOS Socket编程:传输数据的封包,接收数据后半包、粘包、

    本文链接:https://www.haomeiwen.com/subject/datevxtx.html