Linux——TCP的粘包问题

TCP面向字节流

创建一个TCP的socket,同时在内核中创建一个发送缓冲区和一个接收缓冲区;
*调用write,数据会先写入发送缓冲区中;
*如果发送的字节数太长,会被拆分成多个TCP的数据包发出;
*如果发送的字节数太短,就会现在缓冲区里等着,等到缓冲区长度差不多了,或者其他合适的时机发送出去;
接收数据的时候,数据也是从网卡驱动程序到达内核的接收缓冲区;
然后应用程序可以调用read从接收缓冲区中拿数据;

另一方面,TCP的一个连接,既有发送缓冲区,也有接收缓冲区,那么对于这样一个连接,既可以读数据,也可以写数据,这个概念叫做全双工。
由于缓冲区的存在,TCP程序的读和写不需要一一匹配
*写一百个数据时,可以调用一次write写100个字节,也可以调用100次write,一次写一个字节;
*读一百个数据时,也完全不需要烤炉写的时候是怎么写的,既可以一次read100个字节,也可以一次read一个字节,read100次

粘包问题

首先要明确,粘包问题中的包指的是数据包
在TCP的协议头中,没有如同UDP一样的报文长度这样的字段,但是有一个序号这样的字段。
站在传输层的角度,TCP是一个一个报文过来的,按照序号排好序放在缓冲区中,
站在应用层角度,看到的只是一串连续的字节数据。
那么应用程序看到了这么一连串的字节数据,就不知道从哪个部分开始到哪个部分,是一个完整的应用层数据包。

粘包问题的常见原因

最常见的有三种情况:
1:因为发送数据包是,每次发的包小,因为系统进行优化算法,就将两次的包放在一起发送,减少了资源的重复占用,多次发送回经历多次网络延迟,一起发送回减少网络延迟的次数。因此在发送小数据时会将两次数据一起发送,而客户端接收时会一并接收。服务器在接收到信息,就无法区分那些数据包是客户端自己分开发送的;
2:服务器在接收到数据后,放到缓冲区中,但是消息没有及时从缓冲区中取走,下次再取输的时候就可能会出现一次取出多个数据包的情况;
3:也可能受MTU,mss影响TCP在传输前进行拆包,出现粘包问题

那么我们该如何避免粘包问题呢?

归根结底就是一句话,明确两个包之间的边界。
*对于定长的包,保证每次都按固定大小读取即可;
*对于变长的包,可以在包头位置,约定一个包总长度的字段,从而就知道了包结束的位置;
对于变长的包,还可以在包与包之间使用明确的分隔符

猜你喜欢

转载自blog.csdn.net/yummy_alice/article/details/81233239