当前位置: 首页 > 知识库问答 >
问题:

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

凌声
2023-03-14

我试图理解RFC 7230中提到的TCP重置问题:HTTP/1.1消息语法和路由,第6.6节:

6.6.拆卸

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

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

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

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

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

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

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

因此,服务器通过在最后一个HTTP响应中添加connection:closeheader字段来发出关闭连接的信号,并关闭连接。但它只有在收到确认客户端收到HTTP响应的消息后才关闭连接?

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

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

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

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

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

共有1个答案

戚建德
2023-03-14

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

使用HTTP流水线,即使尚未收到前一个请求的响应(因此此响应中的<code>Connection:close</code>),客户端也可以发送新请求。这是一个轻微的优化,因为只在收到上一个请求的响应后发送下一个请求,但这会带来服务器无法处理此新请求的风险。

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

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

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

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

 类似资料:
  • 问题解决了在这种环境下

  • 这里应该如何处理border重复加粗问题?

  • 问题内容: 下面的程序引发NullPointerException。在Log cat中,它显示: 单击该按钮时,它不会进入Mousefragment类。我试图解决它,但是我不能-如何解决这个问题? 编辑 单击该按钮多少次,该异常随同invalid_ip Toast消息一起显示 问题答案: 如前所述,您的问题询问如何解决此问题。 您需要弄清楚在哪里抛出。为此,请查看堆栈跟踪以查看引起问题的行。然后,

  • 问题内容: 我在做一个 用。我有我的输出。有人可以帮我吗?谢谢。 sendMailServlet代码: 在GlassFish 2.1上的输出: 问题答案: 您需要实施一个自定义 现在在 另请查看JavaMail常见问题解答

  • 当我尝试运行应用程序时,它工作正常。但是当我构建签名apk时,出现了错误 失败:构建失败,出现异常。 问题:任务“:app:lintVitalRelease”的执行失败 无法解析配置“:image_picker_android:调试单元测试运行时类路径”的所有项目。无法转换 bcprov-jdk15on-1.68.jar (org.bouncycastle:bcprov-jdk15on:1.68)

  • 问题内容: 这个问题已经在这里有了答案 : 浮点数学运算是否损坏? (31个答案) 4年前关闭。 使用Math.cos函数在Java中计算余弦90时遇到一些问题: } 当我计算cos90或cos270时,它给了我荒谬的值。应该为0。我使用91或271测试,给出了接近0的正确值。 我应该怎么做才能使cos 90的输出= 0?因此,它使输出x = 0和y = 4。 谢谢建议 问题答案: 您所得到的很有