Socket粘包处理

作者: 聪莞 | 来源:发表于2019-03-29 15:42 被阅读54次

什么是粘包

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

  • TCP(Transport Control Protocol,传输控制协议)是面向连接的,面向流的。TCP的收发两端都要有成对的Socket,因此,发送端为了将更多有效的包发送出去,采用了合并优化算法(Nagle算法),将多次、间隔时间短、数据量小的数据合并为一个大的数据块,进行封包处理。这样的包对于接收端来说,就没办法分辨,所以需要一些特殊的拆包机制。
  • UDP(User Datagram Protocol,用户数据报协议)是无连接的,面向消息的提供高效率服务。不会使用合并优化算法。UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。

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

如何处理粘包

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

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

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

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

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

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

  • 发送数据
    以传输字符串 ”hello“ 为例:
    //要传输的数据
    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];
    }
    

相关文章

  • Socket粘包处理

  • Socket粘包处理

    什么是粘包 TCP有粘包现象,而UDP不会出现粘包。 TCP(Transport Control Protocol...

  • 即时通讯

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

  • socket 粘包拆包处理

    粘包、拆包? 客户端或者服务端不断的发送数据包时,接收的数据会出现两个数据包粘在一起的情况,这就是TCP协议中经常...

  • ios开发中的包的处理

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

  • iOS Socket封包、粘包、拆包处理

    一、封包 在iOS很多应用开发中,大部分用的网络通信都是http/https协议,除非有特殊的需求会用到Socke...

  • Socket粘包和拆包处理思路

    一旦客户端和服务器建立了Socket通信连接,接下来粘包和拆包就是一个必须要考虑的问题 本文是关于使用TCP协议下...

  • 关于Socket 中粘包的处理

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

  • TCP粘包拆包

    TCP粘包拆包定义 拆包和粘包是在socket编程中经常出现的情况,在socket通讯过程中,如果通讯的一端一次性...

  • 使用TCP收发消息需要处理的常见问题

    要实现服务器和客户端之间完整的收发消息,需要处理以下的几个问题。 粘包半包问题 粘包就是一次从socket缓冲区中...

网友评论

    本文标题:Socket粘包处理

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