TCP粘包、拆包与通信协议详解
另外需要注意的是:对于本地回环地址(lookback)不需要走以太网,所以不受到以太网MTU=1500的限制。linux服务器上输入ifconfig命令,可以查看不同网卡的MTU大小,如下: 上图显示了2个网卡信息:
2.3 Nagle算法 TCP/IP协议中,无论发送多少数据,总是要在数据(DATA)前面加上协议头(TCP Header+IP Header),同时,对方接收到数据,也需要发送ACK表示确认。 即使从键盘输入的一个字符,占用一个字节,可能在传输上造成41字节的包,其中包括1字节的有用信息和40字节的首部数据。这种情况转变成了4000%的消耗,这样的情况对于重负载的网络来是无法接受的。称之为"糊涂窗口综合征"。 为了尽可能的利用网络带宽,TCP总是希望尽可能的发送足够大的数据。(一个连接会设置MSS参数,因此,TCP/IP希望每次都能够以MSS尺寸的数据块来发送数据)。Nagle算法就是为了尽可能发送大块数据,避免网络中充斥着许多小数据块。 Nagle算法的基本定义是任意时刻,最多只能有一个未被确认的小段。 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。 Nagle算法的规则:
3 通信协议 在了解了粘包、拆包产生的原因之后,现在来分析接收方如何对此进行区分。道理很简单,如果存在不完整的数据(拆包),则需要继续等待数据,直至可以构成一条完整的请求或者响应。 通过定义通信协议(protocol),可以解决粘包、拆包问题。协议的作用就定义传输数据的格式。这样在接受到的数据的时候: 如果粘包了,就可以根据这个格式来区分不同的包 如果拆包了,就等待数据可以构成一个完整的消息来处理。 3.1 定长协议 定长协议:顾名思义,就是指定一个报文的必须具有固定的长度。例如,我们规定每3个字节,表示一个有效报文,如果我们分4次总共发送以下9个字节:
那么根据协议,我们可以判断出来,这里包含了3个有效的请求报文,如下:
在定长协议中:
提示:Netty中提供了FixedLengthFrameDecoder,支持把固定的长度的字节数当做一个完整的消息进行解码 3.2 特殊字符分隔符协议 在包尾部增加回车或者空格符等特殊字符进行分割 。例如,按行解析,遇到字符n、rn的时候,就认为是一个完整的数据包。对于以下二进制字节流:
那么根据协议,我们可以判断出来,这里包含了2个有效的请求报文
在特殊字符分隔符协议中:
在使用特殊字符分隔符协议的时候,需要注意的是,我们选择的特殊字符,一定不能在消息体中出现,否则可能会出现错误的拆包。例如,发送方希望把”12rn34”,当成一个完整的报文,如果是按行拆分,那么就会错误的拆分为2个报文。一种解决策略是,发送方对需要发送的内容预先进行base64编码,由于base64编码只包含64个字符:0-9、a-z、A-Z、+、/,我们可以选择这64个字符之外的特殊字符作为分隔符。 提示:netty中提供了DelimiterBasedFrameDecoder根据特殊字符进行解码。事实上,我们熟悉的的缓存服务器redis,也是通过换行符来区分一个完整的报文。 3.3 变长协议 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |