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

How does HTTP/1.1 solve the TCP reset problem?

我正在尝试了解 RFC 7230: HTTP/1.1 Message Syntax and Routing, § 6.6 中提到的 TCP 重置问题:

6.6. Tear-down

The Connection header field (Section 6.1) provides a "close" connection option that a sender SHOULD send when it wishes to close the connection after the current request/response pair.

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

A client that sends a "close" connection option MUST NOT send further requests on that connection (after the one containing "close") and MUST close the connection after reading the final response message corresponding to this request.

A server that receives a "close" connection option MUST initiate a close of the connection (see below) after it sends the final response to the request that contained "close". The server SHOULD send a "close" connection option in its final response on that connection. The server MUST NOT process any further requests received on that connection.

因此 客户端 通过将 Connection: close header 字段添加到最后一个 HTTP 请求来发出它将关闭连接的信号,它仅在收到确认服务器已收到请求的 HTTP 响应后才关闭连接。

A server that sends a "close" connection option MUST initiate a close of the connection (see below) after it sends the response containing "close". The server MUST NOT process any further requests received on that connection.

A client that receives a "close" connection option MUST cease sending requests on that connection and close the connection after reading the response message containing the "close"; if additional pipelined requests had been sent on the connection, the client SHOULD NOT assume that they will be processed by the server.

所以服务器通过将Connection: close header字段添加到最后一个HTTP 响应[=]来表示它将关闭连接=53=],然后关闭连接。 但是它只有在收到确认客户端收到 HTTP 响应的消息后才关闭连接?

If a server performs an immediate close of a TCP connection, there is a significant risk that the client will not be able to read the last HTTP response. If the server receives additional data from the client on a fully closed connection, such as another request that was sent by the client before receiving the server's response, the server's TCP stack will send a reset packet to the client; unfortunately, the reset packet might erase the client's unacknowledged input buffers before they can be read and interpreted by the client's HTTP parser.

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

To avoid the TCP reset problem, servers typically close a connection in stages. First, the server performs a half-close by closing only the write side of the read/write connection. The server then continues to read from the connection until it receives a corresponding close by the client, or until the server is reasonably certain that its own TCP stack has received the client's acknowledgement of the packet(s) containing the server's last response. Finally, the server fully closes the connection.

因此在服务器发起关闭连接的情况下,服务器仅在发送带有 Connection: close header 字段添加到初始 HTTP 请求,并且只有在收到后续相应的带有 Connection: close header 字段或等待足够长的时间后 假设 它收到了一条 TCP 消息,确认客户端收到了 HTTP 响应。 但是为什么客户端在收到带有Connection: close header字段的HTTP响应后,会发送带有Connection: close header字段的后续相应HTTP请求,而段落5 个状态:“接收到“关闭”连接选项的客户端必须停止在该连接上发送请求”?

It is unknown whether the reset problem is exclusive to TCP or might also be found in other transport connection protocols.

But why would the client send a subsequent corresponding HTTP request with a Connection: close header field after receiving the HTTP response with a Connection: close header field, whereas paragraph 5 states: ‘A client that receives a "close" connection option MUST cease sending requests on that connection’?

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

But how can the TCP reset packet response to the subsequent HTTP request precede the HTTP response to the initial HTTP request?

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

But it closes the connection only after receiving which message acknowledging that the client received the HTTP response?

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