前面一直在嚷嚷 TCP 协议,却一直不知道它到底是个什么东西。用举例来说明:
你和你对象(没有对象那就选你上铺或下铺的同学吧)发短信,事先约定,你给他发送任何短信,TA 都得回复你一句:收到。我想这个在你平时生活中应该有所遇到。
比如你发送“早安”给 TA,TA 会回复你:“收到”。如果过了 1 分钟你还没有收到 TA 的回复(也许是你发送的短信 TA 没收到,也许是 TA 已经回复了,但是因为网络原因你没收到),你就再发送一次“早安”给 TA,直到 TA 回复你为止。
这样就可以保证,你对象一定能收到“早安”两个字!
TCP 协议正是这样一种约定,它能够可靠的保证,发送的数据能够被对端收到。那么具体的,TCP 又是怎么来做这种事情呢?在此之间,我们得先学习 遵守 TCP 协议数据格式,一般称为 TCP 首部或 TCP 头。
2. TCP 首部格式图 1 就展示了 TCP 首部的数据格式。把一整个 TCP 首部+数据部分称为一个 TCP 段。这个图希望大家能记住,并画上个 10 到 20 遍。
图1 TCP 首部格式图 2 就是我们在上一篇博客实验中抓取到一个数据包。
图2 抓到的一个数据包我们只关心 TCP 的部分,也就是图 2 中右侧被圈起来的部分。而左侧就是 OmniPeek 对这部分数据的解析。这个数据包我保存在 unp/protocol/data 文件夹下面,你可以直接下载到你的 windows 下,用 OmniPeek 打开。
3. TCP 段数据分析现在我们手工分析一下这一串二进制数据:
11 34 13 88 8D D3 93 3C 02 8A 7A E2 50 18 41 37 45 AF 00 00 68 65 6C 6C 6F 00为了看的更加清楚,我们把它放到表格里看:
图3 TCP 段数据按照 TCP 的数据格式:
源端口,0x1134,即 10 进制的 4404 端口。
目的端口,0x1388,即 10 进制的 5000 端口。
32 位序号,0x8dd3939c,即 10 进制的 2379453244.
32 位确认序号,0x028a7ae2,即 10 进制的 42629858.
这部分包含了 4 位首部长度,保留位和 6 个标志位。需要拆分来看,[12, 14) 字节的数据是 0x50 和 0x18,即 0101-0000-0001-1000.
图4 [12, 14) 字节分析很容易看出,首部长度为 5,为什么是 5 呢?实际上,首部长度的单位不是字节,而是四字节,因此长度 5 就表示 5 个四字节,即 20 字节。另外,还可以看到标志位中的 ACK 和 PSH 标志被置位了。
这部分表示窗口大小,0x4137,即 10 进制 16695,它发送这个 TCP 段的那一方(即端口 4404 那一方)接收窗口的大小为 16695 个字节。
首部校验和,0x45af,校验和计算的是“伪首部+TCP 首部”这两部分在一起的二进制反码和,这一块同学们不必过多的深究它。
紧急指针,0x0000,只有 URG 标志置位了,这个指针才有用。使用这个值加上序号的值,就是紧急数据的位置。
数据部分,字节流,68 65 6c 6c 6f 00,即 hello\0.
对比一下图 2 中左侧部分,是不是和我们分析一结果一致?如果不一致,那就检查一下你哪里算的不对。注意,在这个 TCP 段中,没有可选项。有些段是包含可选项的。
现在我们已经分析出了所有字段的具体值,但是这些字段到底表示什么含义我们却不清楚。大家先不要着急,先学会分析具体的值,后面的事情,我们慢慢来。
4. 总结