Window网络编程之粘包和拆包

发送与接收

在TCP的Socket中有两个缓冲区分别是发送缓冲区(SO_SNDBUF)接收缓冲区(SO_RCVBUF)

SO_SNDBUF

每次程序调用send发送数据时将要发送的数据先拷贝到发送缓冲区中,然后send函数返回了。也就是说,send函数结束后数据可能并没有发送到对端,仅仅是把应用层的buffer中的数据放到了socket内核的缓冲区。

SO_RCVBUF

接收数据后会将数据存放到socket内核接收缓冲区,当程序调用recv函数后将缓冲区的数据读取到应用程序的内存中进行处理。也就是说,不管有没有调用recv函数底层的接收缓冲区都会接收数据,

粘包和拆包

在调用send和recv后一个是不一定立刻发送到对端,另一个是不一定立刻读取到应用。当全部数据拷贝到发送缓冲区后一次性发送出去时,可能造成数据包粘包。当缓冲区在没有将数据发送出去前就被拷贝满了,可能造成数据包拆包,具体如下所示:
粘包和拆包演示

拆包粘包是在socket编程中经常出现的情况,在socket通讯过程中,如果通讯的一端一次性连续发送多条数据包TCP协议会将多个数据包打包成一个TCP报文发送出去,称为粘包。而如果通讯的一端发送的数据包超过一次TCP报文所能传输的最大值时TCP协议会将一个数据包拆成多个TCP报文分开传输,称为拆包。

Nagle算法

MTU

泛指通讯协议中的最大传输单元。一般用来说明TCP/IP四层协议中数据链路层的最大传输单元,不同类型的网络MTU也会不同,我们普遍使用的以太网的MTU是1500,即最大只能传输1500字节的数据帧。可以通过ifconfig命令查看电脑各个网卡的MTU。

MTU

指TCP建立连接后双方约定的可传输的最大TCP报文长度,是TCP用来限制应用层可发送的最大字节数。因此,如果底层的MTU是1500字节,则:

MSS = 1500 - 20(IP Header) -20 (TCP Header) = 1460 byte。

传输优化

TCP/IP协议中,无论发送多少数据,总是要在数据(DATA)前面加上40字节的协议头,对方接收到数据,也需要发送ACK表示确认。因此,即使只发送了一个字节的数据发送时就变成了41个字节,这就造成了网络传输的浪费。

为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。

算法规则

  • 如果SO_SNDBUF中的数据长度达到MSS,则允许发送

  • 如果该SO_SNDBUF中含有FIN,表示请求关闭连接,则先将SO_SNDBUF中的剩余数据发送,再关闭

  • 设置了TCP_NODELAY = true选项,则允许发送。TCP_NODELAY是取消TCP的确认延迟机制,相当于禁用Negale算法

  • 未设置TCP_CORK选项时,若所有发出去的小数据包,即包长度小于MSS,均被确认,则允许发送

  • 上述条件都未满足,但发生了超时,则立即发送

处理方式

定长协议

每次发送的字节数是固定大小,而接收端在处理数据包的时候只按照固定大小取出数据包,如果不够长度可能发生了拆包,则等待下次数据到来后进行拼包。

变长协议

发送数据时在发送的实际内容之前添加一个整数表示二进制字节的长度,接收数据则先取出整数,根据整数的数值大小取出完整数据包。

Netty中的TCP粘包拆包问题是由于底层的TCP协议无法理解上层的业务数据而导致的。为了解决这个问题,Netty提供了几种解决方案。其中,常用的解决方案有四种[1]: 1. 固定长度的拆包器(FixedLengthFrameDecoder):将每个应用层数据包拆分成固定长度的大小。这种拆包器适用于应用层数据包长度固定的情况。 2. 行拆包器(LineBasedFrameDecoder):将每个应用层数据包以换行符作为分隔符进行分割拆分。这种拆包器适用于应用层数据包以换行符作为结束符的情况。 3. 分隔符拆包器(DelimiterBasedFrameDecoder):将每个应用层数据包通过自定义的分隔符进行分割拆分。这种拆包器适用于应用层数据包以特定分隔符作为结束标志的情况。 4. 基于数据包长度的拆包器(LengthFieldBasedFrameDecoder):将应用层数据包的长度作为接收端应用层数据包的拆分依据。根据应用层协议中包含的数据包长度进行拆包。这种拆包器适用于应用层协议中包含数据包长度的情况。 除了使用这些拆包器,还可以根据业界主流协议的解决方案来解决粘包拆包问题[3]: 1. 消息长度固定:累计读取到长度和为定长LEN的报文后,就认为读取到了一个完整的信息。 2. 使用特殊的分隔符:将换行符或其他特殊的分隔符作为消息的结束标志。 3. 在消息头中定义长度字段:通过在消息头中定义长度字段来标识消息的总长度。 综上所述,Netty提供了多种解决方案来解决TCP粘包拆包问题,可以根据具体的业务需求选择合适的解决方案[1][3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值