1. 诡异的tcp拆包现象

Introduction

想一个问题, 假设HTTP(应用层)要你发送一个2000字节长度的消息, 这个消息是怎么发送的?

IP层分包

IP负责路由寻址, 路径上的所有设备帮你转发包, 但是每个设备都有MTU, 也就是一条消息的最大长度, 如上图所示, 假设路径上所有的设备MTU1500, 但是中间一个是1200,

那么包转发到他那儿的时候, 这个包自然是过不了的, 他会还你一个ICMP包, 里面包含了自己MTU的信息, 然后源主机就会用这个新的MTU重新发一遍消息, 直到消息已经抵达目的主机

IP协议的切包对上层是透明的, 也就是说上层不知道, 比如应用层让UDP发一个2000字节的消息, UDP就尝试去发, IP层把这个2000长度的消息切成两段, 每段套一个IP头, 这件事UDP层是完全不知道的.

TCP层分包

问题就出在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了, 后面的内容需要拆成第二个包来发了

Last updated

Was this helpful?