HTTP/1.1如何解决TCP重置问题?

Mag*_*ero 2 sockets network-programming tcp http persistent-connection

我试图理解RFC 7230中提到的TCP 重置问题: HTTP/1.1 Message Syntax and Routing , \xc2\xa7 6.6

\n
\n

6.6. 拆除

\n

连接头字段(第 6.1 节)提供了一个“关闭”连接选项,当发送方希望在当前请求/响应对之后关闭连接时,应发送该选项。

\n
\n

因此 HTTP/1.1 具有持久连接,这意味着可以在同一个连接上发送多个 HTTP 请求/响应对。

\n
\n

发送“关闭”连接选项的客户端不得在该连接上发送\n进一步的请求(在包含“关闭”的请求之后),并且\n必须在读取与此请求相对应的最终响应消息\n后关闭连接。

\n

接收“关闭”连接选项的服务器必须在发送包含“关闭”的请求的最终响应后启动连接关闭(见下文)。服务器应该在该连接上的最终响应中发送“关闭”连接选项。服务器不得处理该连接上收到的任何进一步的请求。

\n
\n

因此,客户端Connection: close通过在最后一个 HTTP请求中添加标头字段来发出关闭连接的信号,并且只有在收到确认服务器收到请求的 HTTP 响应后才会关闭连接。

\n
\n

发送“关闭”连接选项的服务器必须在发送包含“关闭”的响应后启动连接的关闭(见下文)。服务器不得处理该连接上收到的任何进一步的请求。

\n

接收“关闭”连接选项的客户端必须停止在该连接上发送\n请求,并在读取\n包含“关闭”的响应消息后关闭连接;如果在连接上发送了额外的管道请求,客户端不应该假设它们将由服务器处理。

\n
\n

因此,服务器Connection: close通过将标头字段添加到最后一个 HTTP响应来发出将关闭连接的信号,然后关闭连接。但是只有在收到确认客户端收到 HTTP 响应的消息后才关闭连接?

\n
\n

如果服务器立即关闭 TCP 连接,\n则存在客户端无法读取最后\nHTTP 响应的重大风险。如果服务器在完全关闭的连接中从客户端接收到其他数据,例如客户端在收到服务器响应之前发送的另一个请求,则服务器的 TCP 堆栈将发送一个重置数据包到客户端; 不幸的是,重置数据包可能会在客户端的 HTTP 解析器读取和解释客户端未确认的输入缓冲区之前将其擦除。

\n
\n

因此,在服务器发起关闭连接的情况下,如果服务器在向初始 HTTP 请求发送带有标头字段的 HTTP 响应后立即Connection: close完全关闭连接,则客户端可能不会收到该 HTTP 响应,因为它收到了TCP 重置数据包响应其在初始 HTTP 请求之后发送的后续 HTTP 请求。但是,TCP 重置数据包对后续HTTP 请求的响应如何先于对初始HTTP 请求的 HTTP 响应呢?

\n
\n

为了避免 TCP 重置问题,服务器通常会分阶段关闭连接。首先,服务器通过仅关闭读/写连接的写入端来执行半关闭。然后,服务器\n继续从连接中读取数据,直到收到客户端\n相应的关闭消息,或者直到服务器\n合理地确定其自己的 TCP 堆栈已收到客户端\n对包含以下内容的数据包的确认:服务器的最后\n响应。最后,服务器完全关闭连接。

\n
\n

因此,在服务器发起关闭连接的情况下,服务器仅在向初始 HTTP 请求发送带有标头字段的 HTTP 响应后立即关闭连接的写入Connection: close,并且仅关闭连接的读取端在接收到带有标头字段的后续相应 HTTP 请求之后Connection: close,或者在等待足够长的时间后假设它收到了确认客户端收到 HTTP 响应的 TCP 消息。但是为什么客户端Connection: close在收到带有头字段的 HTTP 响应后会发送后续相应的带有Connection: close头字段的 HTTP 请求,而第 5 段规定: \xe2\x80\x98A 收到“关闭”连接选项的客户端必须停止发送请求那个连接\xe2\x80\x99?

\n
\n

目前尚不清楚重置问题是否是 TCP 所独有的,或者也可能存在于其他传输连接协议中。

\n
\n

Ste*_*ich 5

\n

但是为什么客户端在收到带有 Connection: close 标头字段的 HTTP 响应后会发送带有 Connection: close 标头字段的后续相应 HTTP 请求,而第 5 段指出: \xe2\x80\x98A 接收“关闭”连接的客户端选项必须停止在该连接\xe2\x80\x99 上发送请求吗?

\n
\n

Connection: close通过 HTTP 管道,即使尚未收到先前请求的响应(以及此响应中的响应),客户端也可以发送新请求。与仅在收到前一个请求的响应后发送下一个请求相比,这是一个轻微的优化,但它带来了服务器不会处理此新请求的风险。

\n
\n

但是,TCP 重置数据包对后续 HTTP 请求的响应如何先于对初始 HTTP 请求的 HTTP 响应呢?

\n
\n

虽然 TCP RST 将在响应之后发送,但它会提前传播到应用程序。如果新数据到达已关闭至少用于读取的套接字(即 或close(fd)) ,则发送 TCP RST shutdown(fd, SHUT_RD)。如果关闭时套接字的接收缓冲区中仍有未处理的数据,即像 HTTP 管道传输的情况一样,它也会被发送。一旦对等方收到 TCP RST,其套接字将被标记为损坏。在使用此套接字的下一个系统调用(即通常为readwrite)时,无论套接字的接收缓冲区中是否仍有未读数据,此错误都将传递到应用程序\xe2\x80\x94。这些未读数据因此丢失。

\n
\n

但是只有在收到确认客户端收到 HTTP 响应的消息后才关闭连接?

\n
\n

它不等待来自客户端的某些应用程序消息。它将首先使用 传递响应Connection: close,然后在套接字上读取以确定客户端是否关闭连接。然后它也会关闭连接。当然,这种等待关闭应该在较短的超时时间内完成,因为中断的连接可能会导致连接永远不会被显式关闭。或者,它可以只等待几秒钟,并希望客户端同时收到并处理响应。

\n