网络程序员OC-开发案例收集

Socket粘包处理

2019-03-29  本文已影响54人  聪莞

什么是粘包

TCP有粘包现象,而UDP不会出现粘包。

举个例子
我们连续发送三个数据包,大小分别是1k,2k ,4k,这三个数据包,都已经到达了接收端的网络堆栈中,如果使用UDP协议,不管我们使用多大的接收缓冲区去接收数据,我们必须有三次接收动作,才能够把所有的数据包接收完.而使用TCP协议,我们只要把接收的缓冲区大小设置在7k以上,我们就能够一次把所有的数据包接收下来,只需要有一次接收动作。

如何处理粘包

  1. 提前通知接收端要传送的包的长度
    粘包问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。

不建议使用,因为程序的运行速度远快于网络传输速度,所以在发送一段字节前,先用send去发送该字节流长度,这样会放大网络延迟带来的性能损耗

  1. 加分割标识符
    {数据段01}+标识符+{数据段02}+标识符
    发送端和接收端约定好一个标识符来区分不同的数据包,如果接收到了这么一个分隔符,就表示一个完整的包接收完毕。

也不建议使用,因为要发送的数据很多,数据的内容格式也有很多,可能会出现标识符不唯一的情况

  1. 自定义包头(建议使用)
    image.png

在开始传输数据时,在包头拼上自定义的一些信息,比如前4个字节表示包的长度,5-8个字节表示传输的类型(Type:做一些业务区分),后面为实际的数据包。

    //要传输的数据
    NSData * data = [@"hello" dataUsingEncoding:NSUTF8StringEncoding];
    
    //实际传输的数据
    NSMutableData * mData = [NSMutableData data];
    
    //计算数据总长度
    unsigned int totalLength = 4 + 4 + (int)data.length;
    
    //拼前4位
    NSData * lengthData = [NSData dataWithBytes:&totalLength length:4];
    [mData appendData:lengthData];
    
    //拼5-8位
    int type = 1;
    NSData * typeData = [NSData dataWithBytes:&type length:4];
    [mData appendData:typeData];
    
    //拼接最后的data
    [mData appendData:data];
    
    //发送mData
        。。。
@property (nonatomic, strong) NSMutableData  *dataM;            //接收的完整的一个数据包的data
@property (nonatomic, assign) unsigned int totalSize;           //一个完整的数据包大小

    BOOL isNewPackage = self.dataM.length == 0;
    if (isNewPackage) {
        //接收一个新的数据包
        
        //获取总大小
        NSData * totalSizeData = [data subdataWithRange:NSMakeRange(0, 4)];
        unsigned int totalSize = 0;
        [totalSizeData getBytes:&totalSize length:4];
        self.totalSize = totalSize;
        NSLog(@"接收总数据的大小 %u",totalSize);
        
        //获取type
        NSData * typeData = [data subdataWithRange:NSMakeRange(4, 4)];
        unsigned int type = 0;
        [typeData getBytes:&type length:4];
        NSLog(@"接收总数据的类型 %u",type);
        
        //获取数据段
        NSData * realData = [data subdataWithRange:NSMakeRange(8, data.length - 8)];
        [self.dataM appendData:realData];
    }
    else {
        //不是一个新的数据包  直接追加进去
        [self.dataM appendData:data];
    }
 
    //判断是否接收完成
    if (self.dataM.length == self.totalSize - 8) {
        //已经接收完整
        
        //处理data
        NSString * string = [[NSString alloc] initWithData:self.dataM encoding:NSUTF8StringEncoding];
        NSLog(@"接收到的数据为:%@",string);
        
        //dataM重置
        self.dataM = [NSMutableData data];
    }
    
上一篇 下一篇

猜你喜欢

热点阅读