0%

TCP粘包和拆包

TCP粘包和拆包

TCP是面向连接的,面向流的,提供了高可靠性服务,客户端和服务器端都要有一一成对的socket,因此,发送端为了将多个发给接收端的包,更有效的发给对方,使用优化方法(Nagle算法),将多次间隔较少且数据量小的数据,合并成一个大的数据块,然后进行封包,这样做虽然提高了效率,但是接收端就难以分辨出完整的数据包了,因为面向流的通信是无消息保护边界的,所以需要在接收端处理消息边界问题,也就是粘包和拆包问题

粘包产生的原因

  • 操作系统在发送TCP的时候,底层会有一个缓冲区,发送端需要等缓冲区满才发送出去,如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP会将多个请求合并为一个请求进行发送
  • 接收端没有及时读取接收缓冲区的包,造成多个包接收

拆包产生的原因

  • 应用程序write写入的字节大小超过套接字发送缓冲区的大小
  • 待发送数据大于MSS(最大报文长度),TCP会在传输前进行MSS大小的TCP分段
  • 以太网帧的payload大于MTU进行IP分片

解决方法

根本就是解决就是服务器端每次读取长度的问题

有三种方案

  • 消息定长,如果不够,空位补空格,这样接收端每次从接收缓冲区中读取固定长度的数据就可以把每个数据包拆分开 netty中使用的是FixedLengthFrameDecoder来实现定长
  • 在包尾部增加特殊字符进行分割,这样接收端就可以通过这个边界来将数据包拆分开 netty中使用了分隔符类DelimiterBasedFrameDecoder来实现分隔符分隔的,还有LineBasedFrameDecoder是使用换行符来结束,如\n和\r\n
  • 将消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,然后通过读取包首部的长度长度字段,从而知道每一个数据包的实际长度 netty中使用的是LengthFieldPrepender进行编码,LengthFieldBasedFrameDecoder进行解码。还有HTTP中也是使用的消息头来指定Content-Length的

欢迎关注我的其它发布渠道