1. 诡异的tcp拆包现象
Last updated
Was this helpful?
Last updated
Was this helpful?
想一个问题, 假设HTTP(应用层)要你发送一个2000字节长度的消息, 这个消息是怎么发送的?
IP负责路由寻址, 路径上的所有设备帮你转发包, 但是每个设备都有MTU, 也就是一条消息的最大长度, 如上图所示, 假设路径上所有的设备MTU1500, 但是中间一个是1200,
那么包转发到他那儿的时候, 这个包自然是过不了的, 他会还你一个ICMP包, 里面包含了自己MTU的信息, 然后源主机就会用这个新的MTU重新发一遍消息, 直到消息已经抵达目的主机
IP协议的切包对上层是透明的, 也就是说上层不知道, 比如应用层让UDP发一个2000字节的消息, UDP就尝试去发, IP层把这个2000长度的消息切成两段, 每段套一个IP头, 这件事UDP层是完全不知道的.
问题就出在UDP/TCP层对此并不知情, 导致被分开的第二个包是没有TCP头的. 明明是TCP包却没有TCP头. TCP心想要你切不如我自己切, 于是自己搞了一套叫MSS, 代表每条TCP消息的最大长度, 正常情况下是MTU减去20字节的IP头, 以及20字节的TCP头
MSS这一套是内核层面的限制, 双方在握手的时候就会确定本次会话的MSS, 一旦确定了MSS, TCP就会应用层发来的消息拆分, 分成好几个包发走, 每个包都会有报头
上图里, 58186向443端口发出握手请求, 58186这边先自报家门:
我的mss是1460(MTU = 1500减去20IP头, 以及20TCP头)
但443那边出于某种原因, 说那我只有1352哎, 于是商定完成, 从现在开始这段会话使用的mss就是1352, 也就是说这段会话所有的TCP包全都小于1352
后续的会话中, 的确出现了一次1352, 这个时候大小已经到max了, 后面的内容需要拆成第二个包来发了