示例实现过程
1 使用 http-server 创建一个临时的服务器, 链接为 http://127.0.0.1:8080
2 打开 WireShark, 在过滤器中输入如下命令,来过滤出我们所需的包.这条命令表示过滤出 source(来源) 地址或 destination(目的地) 地址为 127.0.0.1:8080 的包.
1 | ip.src==127.0.0.1:8080 or ip.dst==127.0.0.1:8080 |
3 使用任意浏览器窗口访问 http://127.0.0.1:8080 即可.注意等待一段时间后需要关闭窗口,否则可能抓取不到终止TCP连接时的 四次挥手.
下图为一个完整的 TCP 通信流程, 通过 Wireshark 抓包获取.
Wireshark 第三格的数据格式默认为 16 进制, 可通过点击鼠标右键 -> as bits 切换为 2 进制格式
TCP 数据格式
下图是 TCP 数据格式, TCP 部首的大小通常为 20 个字节(20 * 8 = 160 位)(如果不包括 选项 的话)
下图是 Wireshark 抓取的 TCP 部首
TCP 标志
1 URG 紧急指针
2 ACK 确认应答
3 PSH 发送数据
4 RST 重置请求
5 SYN 建立连接,握手时发送
6 FIN 终止连接,挥手时发送
Sequnence Number 序号
初始的 Sequence Number 被称为 ISN(Initial Sequence Number),是一个随机数.
之后的 Sequence Number = 上次发送的 Sequence Number + 上次发送的 TCP payload
Sequnence Number 的作用是判断接收方是否成功收到了数据.
当接收方收到数据时, 返回 ACK 携带 Acknowledgment Number(= Sequnence Number + TCP payload (数据大小)). 发送方通过收到的 Acknowledgment Number 来判断是否发送成功.
以下图客户端的 HTTP 请求为例:
此次的 Sequence Number 为 2873872653
整个数据包大小为 893 字节, Null/Loopback(?) + IP 部首 + TCP 部首(4 + 20 + 20) 为 44 字节.
HTTP 数据为 849 (893 - 44)字节
Null/Loopback:
ip部首:
TCP 部首:
客户端下一次发送的 Sequence Number = 2873873502 (2873872653 + 849)
Acknowledgment Number 确认序号
Acknowledgment Number = 上一次收到的 Sequence Number + 上一次收到的 TCP payload
注意 SYN 和 FIN 也占一个序号,因此 SYN 和 FIN 的 ACK 会 +1
以下图的HTTP请求为例, 客户端向服务器请求根目录下的资源, 发送了如下数据:
Sequence Number 为 2873872653, TCP payload 为 849.
再看看下图服务器的响应,服务器返回 Acknowledgment Number 为 2873873502, 减去 TCP payload 849 正好等于 2873872653
建立TCP连接(三次握手)
握手过程:
1 客户端发送: SYN=1 SequenceNumber=2873872652
2 服务器收到消息(1),向客户端发送: SYN=1 ACK=1 SequneceNumber=3105526224 AcknowledgmentNumber=2873872653
3 客户端收到消息(2),向服务器发送: ACK=1 SequenceNumber=2873872653 AcknowledgmentNumber=3105526225
终止TCP连接(四次挥手)
挥手过程:
1 服务器发送: FIN=1 ACK=1 SequenceNumber=3105526493 AcknowledgmentNumber=2873873502
2 客户端收到消息(1),向服务器发送 ACK=1 SequenceNumber=2873873502 AcknowledgmentNumber=3105526494
3 客户端发送: FIN=1 ACK=1 SequenceNumber=2873873502 AcknowledgmentNumber=3105526494
4 服务器收到消息(2),向客户端发送 ACK=1 SequenceNumber=3105526494 AcknowledgmentNumber=2873873503
注意: 通信的双方皆可发起FIN来终止TCP连接(一般由客户端发起)
为什么 SYN 和 FIN 的响应 ACK 要 + 1 ?
因为TCP 协议规定, SYN 和 FIN 占用一个序号.
为什么终止TCP连接需要四次?
TCP是全双工协议,通信双方都可以发送数据.
当某一方收到带有FIN标志的消息时,可能还有未发完的数据.此时不能将 ACK 和 FIN 合并.
位和字节
- 位 bit: 计算机的最小单位, 1 bit 只能储存 0 或 1
- 字节 byte: 1 byte = 8 bit
- 1KB = 1024 byte (2^10)