关于 TCP 的 14 个问题

每个TCP数据包都有一个源/目的IP地址吗?

是的

下边是一个TCP数据包的结构

1
2
3
4
5
6
7
8
9
+-+-+-+-+-+-+-+-+--
| Ethernet header |
+-+-+-+-+-+-+-+-+--
| IP header |
+-+-+-+-+-+-+-+-+--
| TCP header |
+-+-+-+-+-+-+-+-+-+
| packet contents |
+-+-+-+-+-+-+-+-+-+

这就是为什么我们称它为 「TCP/IP」– TCP数据包总是有一个 IP 头。

每个TCP数据包都有一个端口号吗?

是的

TCP 头中的端口字段为16位。

TCP连接中发送的第一个数据包是什么?

SYN

每个TCP连接都是以三次向握手开始的:

  • client: SYN
  • server: SYN + ACK
  • client: ACK

如果防火墙拦截了连接,TCP握手能否完成?

不能

被防火墙拦截的常见症状是 SYN 数据包发出后无 ACK 返回。

电子邮件使用TCP吗?

是的

电子邮件是通过SMTP发送的,它使用了 TCP。

FTP、POP3、HTTP/1、HTTP/2、websockets 等很逗互联网协议也都使用了 TCP。

TCP连接是双向的吗?(客户端和服务器都能发送消息吗?)

是的

一个HTTP 请求/响应 是个 TCP 连接 —— 客户端发送 HTTP 请求,然后服务器发送响应。

如果服务器发送响应给客户端,客户端能否发送更多数据?

是的

例如,websockets 使用 TCP 使客户端和服务器根据需要来回发送数据。

如果你通过TCP发送一个长消息,是否会被分成多个数据包?

是的

数据包有最大限制(通常是1500字节),所以需要将一个 TCP 消息分割成许多数据包。

当你发送 TCP 数据包时,数据包是否可以按照你发送的顺序到达目的地?

不是

无法确保网络数据包会按照你发送的顺序到达。

负责理解TCP协议的代码在哪?

通常是在操作系统中

Linux、Mac、Windows等都有 TCP 实现。如果你愿意,也可以编写自己的TCP实现。

你的操作系统使用 TCP 数据包中的哪个字段将数据包按正确顺序排列?

序列号(sequence number)

数据包的序列号告诉你它在整个数据流中的位置。序列号计算的是字节数,而不是包数。

下面是一组数据包内容和序列号的例子(每个字符是1个字节):

1
2
3
4
5
6
7
8
9
+-+-+-+-+-+-+-+-+-+-+-
| contents | seq # |
+-+-+-+-+-+-+-+-+-+-+-
| hello I | 0 |
+-+-+-+-+-+-+-+-+-+-+-
| x! | 15 |
+-+-+-+-+-+-+-+-+-+-+-
| 'm panma | 7 |
+-+-+-+-+-+-+-+-+-+-+-

如果按照正确的顺序排列,这些数据包将重新排列为“hello I’m panmax!”

顺序号总是从0开始吗?

不是

通常连接中的第一个序列号是一个很大的数字,比如:1737132723,其他序列号都是与这个数字相对的。所以在计算时需要减去第一个序列号。

如果你在 Wireshark/tcpdump 中查看TCP数据包,它们会进行减法处理,使其看起来像序列号从0开始,让人类更易阅读。

如果你发送一个 TCP 数据包,如何知道它被接收?

你会收到一个ACK

例如,服务器收到了一个序列号为1200的数据包,并且也已收到所有在它之前的数据包,服务器会发送一个序列号为1200的ACK数据包。

被丢弃的TCP数据包是否会被重试发送?

是的

如果客户端(或服务器)在一定时间内没有收到其发送数据包的ACK,它将会重试发送该数据包。