TCP通信“粘包问题”及其解决办法

1. TCP通讯“粘包问题”

使用TCP通讯时,需要考虑TCP通讯的“粘包问题”。

“粘包问题”的本质就是数据读取边界错误所致。例如发送端发送了3次数据,分别是“1111”, 2222”, 3333”,接收端可能接受2次数据,分别是“111122”,“223333”,抑或“11112222”和“3333”。

产生上述“问题”的本质原因TCP是基于字节流而不是消息包的协议,TCP会把数据变成字节流发到对方去,而且保证顺序不会乱。

具体原因

1)发送方原因

TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:

a.只有上一个分组得到确认,才会发送下一个分组

b. 收集多个小分组,在一个确认到来时一起发送

Nagle算法造成了发送方可能会出现粘包问题

2)接收方原因

TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。实际上,TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。

综上,这就需要在应用层确定数据边界,搞定字节流解析,解决“粘包问题”(上文“粘包问题”4字一直加上了引号,是因为这其实不是问题,是TCP基于字节流通讯的特性,本来就应该在应用层完成字节流的解析)。

 

2. 解决办法

如上所述,需要在应用层搞定字节流解析,确定数据边界,解决“粘包问题”。

在应用层确定数据边界,完成字节流解析主要有3种方法,分别是

(1)发送固定长度的消息

(2)把消息的尺寸与消息一块发送

(3)使用特殊标记来区分消息间隔

第一种“发送固定长度的消息”的方法,一般局限性较大,不推荐使用该方法。下面给出将第二种和第三种结合起来确定数据边界,做字节流解析的方法。

双方约定通讯格式为:HEAD××数据包,其中

a.HEAD为特殊标记,用来做消息分割(双方要约定数据包不包含消息分隔符HEAD,否则会造成数据解析错误)

b. xx为N个字节的数据长度

c. 数据包为实际的数据内容。

发送方按照该格式做数据封包,接受者按照该格式解析数据。

HEAD作为特殊标记分割了各个消息,之后解析出数据长度后,按照该长度解析后面的数据,通过数据长度也可以知道本次接收到的消息是不是完整的消息。

 

3. 问题扩展

1)什么时候需要处理“粘包问题”

a. 如果发送方发送的多组数据本来就是同一块数据的不同部分,比如说一个文件被分成多个部分发送,这时当然不需要处理粘包现象

b. 如果多个分组毫不相干,甚至是并列关系,那么这个时候就一定要处理粘包现象了

2) UDP通信会不会粘包

TCP为了保证可靠传输并减少额外的开销(每次发包都要验证),采用了基于流的传输,基于流的传输不认为消息是一条一条的,是无保护消息边界的(保护消息边界:指传输协议把数据当做一条独立的消息在网上传输,接收端一次只能接受一条独立的消息)。UDP则是面向消息传输的,是有保护消息边界的,接收方一次只接受一条独立的信息,所以不存在粘包问题。

3)TCP可靠、UDP不可靠的原因

a. TCP可靠数据传输原理

每个Tcp socket在内核中都有一个发送缓冲区和一个接受缓冲区。tcp协议要求对端在接受到tcp数据报之后,要对其序号进行ACK,只有当接受到一个tcp数据报的ACK之后,才可以把这个tcp数据报从socket的发送缓冲区清除,另外tcp还有一个流量控制功能,tcp的socket接受缓冲区接受到网络上来的数据缓存起来后,如果应用程序一直没有读取,socket接受缓冲区满了之后,发生的动作是:通知对端TCP协议中的窗口关闭,这便是滑动窗口的实现,保证TCP socket接受缓冲区不会溢出,因为对方不允许发送超过所通知窗口大小的数据, 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接收方TCP将丢弃它。这两点保证了tcp是可靠传输的。

b. UDP不可靠数据传输原理

UDP只有一个socket接受缓冲区,没有socket发送缓冲区,即只要有数据就发,不管对方是否可以正确接受。而在对方的socket接受缓冲区满了之后,新来的数据报无法进入到socket接受缓冲区,此数据报就会被丢弃,udp是没有流量控制的,故UDP的数据传输是不可靠的。

 

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值