TCP 如何处理针对一个端口的多个请求?

TCP 如何处理针对一个端口的多个请求?

由于服务器可能同时从客户端收到许多针对特定端口的请求(例如 HTTP 对象的端口 80),那么服务器如何处理同时发出的请求?

答案1

TCP 并没有真正定义“请求”是什么样子;作为运输协议它只提供双工数据流(与通过串行端口的数据传输没有区别),并将其余部分留给应用程序来完成。

这也意味着请求不是针对某个端口的;它们是针对通过特定连接(数据流)发送。单个 TCP 数据包本身没有任何意义;它们总是被重新组装成一个连续的数据流。你已经注意到每个数据包都带有目的地源端口号,标识它属于特定连接。(注意:它们不能准确区分特定客户端,因为单个客户端可能会打开多个连接;相反,它们可以区分特定的数据流。)

因此,这个问题实际上与端口无关——剩下唯一要问的是通过 TCP 运行的协议如何区分通过同一连接发送多个请求。


有些协议从一开始就不是面向请求的 - 它们可能是面向命令的,例如 FTP 或 SMTP;或者它们可能有带响应和不带响应的请求混合,例如 SSH;或者它们可能传输非结构化数据,这些数据看起来根本不像由不同的请求组成,例如简单的 Telnet。

某些协议(如 HTTP/1.0、Gopher 或 WHOIS)仅允许每个连接发送一个请求。服务器发送响应后,它就会关闭连接,客户端必须再次连接(使用新的 TCP 源/目标端口对)。

HTTP/1.1 支持长连接,但每次仍只能发送一个请求。客户端必须等待第一个响应完成后才能发送第二个请求。(并且现在需要区分多个响应:对于常规资源,HTTP 客户端使用“Content-Length”标头来知道响应何时完成,并且使用“分块”格式发送“不确定长度”响应。)

HTTP/1.1 中还有一个扩展,称为“流水线”,允许将多个请求堆叠起来并同时发送。其机制很简单:响应以与请求完全相同的顺序到达。(但请注意,尽管大多数 HTTP 客户端使用长连接,但它们不要使用 HTTP 管道,因为事实证明它带来的问题比解决方案还多。

一些协议在 TCP 提供的流之上添加了自己的多路复用。目前最著名的例子是 HTTP/2,它在单个 TCP 连接上有一个“流”系统——每个请求和响应都被分配了自己的流,分成小块,每个块都带有长度和流 ID。接收方可以通过根据流 ID 重新组装多个请求来区分它们……这实际上反映了 TCP 的工作方式。

其他协议(如 DNS)更简单,但具有相同的一般概念;TCP 上的 DNS 请求或响应以其自身的字节长度作为前缀,因此接收方确切知道第一个请求有多少字节,从而知道第二个请求从哪里开始。响应再次带有“请求 ID”,客户端可以知道哪个响应属于哪个请求。


因此一般来说,有两种常见格式用于通过单个 TCP 连接或其他传输流分隔多个请求:

  • 基于行,其中每个数据包都以换行符或其他特殊字符终止或分隔。IRC、FTP(控制)、SMTP 大多是基于行的。

  • 基于长度,其中每个数据包都以其自己的长度(以字节为单位)作为前缀。SSH、DNS、git://、HTTP/2 都是基于长度的。

  • HTTP/1.x 是请求/响应的不幸混合体标题是基于行的,但是身体是基于长度的。

    还有其他怪事,例如 IMAP 是基于行的,除非它不是。

处理多个请求并整理相应的响应(如果协议允许的话)有两种常用的方法:

  • 流水线– 客户端可以提交多个请求按特定顺序,并且响应按照完全相同的顺序到达。

    因此在 HTTP/1.1 中,如果客户端请求页面 A、页面 B、页面 C,则服务器将始终按照此顺序响应页面 A、页面 B 和页面 C。

  • 多路复用– 客户可以单独提交多个请求“请求 ID”,并且响应可能以任何顺序到达,因为每个响应都带有提示它的原始“请求 ID”。

    例如,在 DNS 中,客户端可以请求 google.com/A(请求#1234)和 facebook.com/AAAA(请求#3456),并且服务器可能在处理请求#1234 之前响应请求#3456。

    IMAP 已标记请求/响应,但它也具有服务器可能发送的与任何特定请求无关的未经请求的响应(例如推送通知)。

  • 多路复用也可以与“频道 ID”,就像 HTTP/2 和 SSHv2 中的情况一样。不同之处在于“通道 ID”是长期存在的,并且确实与 TCP 标头中的端口非常相似,而“请求 ID”则是短期存在的。

    在 HTTP/2 中,每个请求都分配有一个流,并且响应可能会交错 - 客户端可能会收到一些标记为“流 A”的数据、一些标记为“流 B”的数据,然后收到流 A 的更多数据。尽管流只携带单个请求/响应,但它们仍然由多个不同的消息组成,因此更像通道 ID。

  • 甚至可能两者兼而有之——例如,协议可能具有多路复用通道,但在每个通道上它可能携带多个标记或流水线请求。

    SSHv2 的工作原理是 - 同一个连接可能有多个交互式 shell 通道(非结构化)、SFTP 通道(流水线请求/响应)、TCP 转发通道(非结构化)、ssh-agent 转发通道(流水线请求/响应)等等。

相关内容