TCP 协议学习笔记 (一)
传输控制协议,洋文叫 Transmission Control Protocol,简称 TCP。TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的 RFC 793 定义。
IP 即 Internet Protocol 是工作在网络层的,其不对网络的可靠性做任何保证,目前互联网中网络的可靠性一般都由 TCP 来保证,所谓可靠性具体来说就是数据传输不丢失、数据顺序不会发生改变。除了可靠性,TCP 还提出了一系列的算法来保证网络数据传输的高效性。
我们先简单的看一下 TCP 报文的数据结构,其中 TCP 报文的头部一般都是 20 个字节,当然根据首部长度字段也可以进行适量的扩充,最大为 60 字节,跟随在头部信息之后的就是 TCP 所携带的数据信息。

我们会从两个大的方面来描述 TCP 的工作方式
- TCP 连接的创建和关闭
- TCP 的数据传输过程
抓取 TCP 的报文信息
为了了解 TCP 的工作方式,我们使用 tcpdump 来抓取 TCP 报文进行分析。首先我们启动一个 HTTP 服务器
$ python -m SimpleHTTPServer 5800
Serving HTTP on 0.0.0.0 port 5800 ...
随后启动 tcpdump 并让其监听指定端口的数据信息
$ tcpdump tcp port 5800 -S
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
最后我们使用 curl 请求 HTTP 服务器
$ curl -v http://172.21.3.92:5800
这次操作使得 tcpdump 获得如下输出
1 | 15:18:45.635203 IP 172.19.3.44.59480 > lin-21-3-92.5800: Flags [S], seq 586172531, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1351103125 ecr 0,sackOK,eol], length 0 |
其中的标志含义如下
| 标志 | 三字符缩写 | 描述 |
|---|---|---|
| S | SYN | 同步序号 |
| F | FIN | 发送方完成数据发送 |
| R | RST | 复位连接 |
| P | PSH | 尽可能快的将数据发往接受进程 |
| . | 以上 4 个标志 bit 均置为零 |
下面我们就基于这次实验的结果来了解 TCP。
TCP 连接的建立
TCP 是一个面向连接的协议,双方在进行数据传输前需要先建立连接,上面的实验的前三行就是所谓的“三次握手”。
- 客户端向服务端发送一个 SYN 的数据,其中的 seq 为 586172531
- 服务端接收到 SYN 报文之后,将报文中的 seq+1 并作为 ACK 返回给客户端
- 服务端自己也生成了一个 seq 并将这个 seq 2988380519 发送给客户端
- 客户端收到了服务端的 seq 之后,将报文中的 seq+1 并作为 ACK 返回给服务端
以上就是建立连接时客户端和服务端之间的数据交互,我们可以看到建立连接时最重要的就是告知对方自己当前的 seq 的值,这个 seq 的初始值随时间变化,不会发生重复。
以上建立连接过程的行为不是需要 4 步操作吗,怎么会称为“三次握手”呢。其实很简单,因为步骤二和步骤三都是由服务端向客户端发送数据,所以这两步操作其实被合并为一步操作了。所以最终三次握手如下
- 客户端发送 seq 给服务端
- 服务端收到 seq,将 seq+1 作为 ACK,并且生成一个自己的 seq,把客户端的 ACK 和服务端的 seq 发送给客户端
- 客户端收到 ACK 并校验,知道服务端已经知道了自己的 seq 了;同时客户端还知道了服务端的 seq,其把服务端的 seq+1 并作为 ACK 返回给服务端,最终服务端知道客户端也已经知道了自己的 seq 了。连接建立成功。
TCP 连接的关闭
建立连接需要 3 次握手,断开连接却需要 4 次挥手,这是因为 TCP 的半关闭特性造成的。简单来说,TCP 允许只关闭某一个方向上的连接。我们知道 TCP 连接是全双工的,而关闭单向的连接之后,另一个方向上的连接还可以正常的发送数据,此时连接变成单工。
上面的报文信息 7、9、10、11 行显示了这个 4 次挥手的过程
- 第 07 行:服务端发送 FIN 标志给客户端
- 第 09 行:客户端收到了 FIN 标志后,将服务端的 seq+1 并返回 ACK 给服务端,此时 服务端->客户端 的连接关闭
- 第 10 行:客户端发送 FIN 标志给服务端
- 第 11 行:服务端收到 FIN 之后,将客户端的 seq+1 并发送 ACK 给客户端,客户端收到了 ACK,客户端->服务端 的连接关闭
TCP 连接断开的过程和连接过程非常相似,区别只在于客户端收到了服务端发送的 FIN 标志后,在发送给服务端的 ACK 中没有附带自己的 FIN 标志,这是 TCP 的半关闭特性所导致的。
需要注意的是一旦 TCP 连接建立成功,此时连接双方在传输数据或者断开连接时,都是处于完全对等的状态,不存在身份上的差别。简单来说客户端发送数据给服务端和服务端发送数据给客户端是一样的;而最终断开连接的操作可以由客户端率先发起,也可以由服务端率先发起,它们也都是一样的。
总结
关于 TCP 的笔记暂时先到这里,我们已经了解了 TCP 连接的建立和关闭,在 下一篇文章 中我们再继续了解一下 TCP 的数据传输过程。
最后放一张 TCP 中连接的状态转移图,这之中的状态变化主要是在连接建立和关闭时所产生的。俺认为作为非网络方向的程序员并不需要记得这张图,只需要在进行网络分析的时候能够对照着这张图进行分析即可,不过俺对自己的要求一向较低,还请读者不要学我。
