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

Nettysocket.shutdownOutput()等价于避免TCP RST?

毋宪
2023-03-14

我想知道是否有一种方法可以避免在Netty中关闭连接时设置TCP RST标志,而不是TCP FIN标志,其中TCP接收缓冲区中还残留着输入数据。

使用案例是:

  • 客户端(用C编写)发送包含许多字段的数据包
  • 服务器读取数据包,在早期字段遇到错误,引发异常
  • 异常处理程序捕获异常,写入错误消息,并将写入时关闭回调添加到写入将来

问题是:

接收缓冲区中的剩余数据会导致Linux(或Java..)用RST标志标记TCP数据包。这会阻止客户端读取数据,因为当客户端开始尝试时,它会发现由于套接字被关闭而出现读取错误。

对于直接的Java套接字,我认为解决方案是调用套接字。关闭前关闭Output()。在Netty中是否有一个等效的函数?

如果我只是继续从套接字读取,则可能不足以避免 RST,因为在调用 close 时缓冲区中可能存在数据,也可能没有数据。

供参考:http://cs.baylor.edu/~donahoo/实用/CSockets/TCPRST.pdf

更新:

问题的另一个参考和描述:http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html

调用ShutdownOutput()应该有助于更有序地关闭连接(通过发送FIN),但是如果客户端仍在发送数据,则无论如何都会发送RST消息(参见EJP的回答)。Netty 4中可能提供了相当于ShutdownOutput()的选项。

解决方案是要么从客户端读取所有数据(但您永远无法确定客户端何时会完全停止发送,尤其是在恶意客户端的情况下),要么在发送响应后简单地等待关闭连接(参见来自不可信的回答)。

共有2个答案

晏正豪
2023-03-14

你能试试这个吗:服务器写入错误消息后,等待500ms,然后关闭()。看看客户端现在是否可以收到错误消息。

我猜测,由于TCP延迟确认,服务器接收缓冲区中的数据包尚未得到确认。如果现在调用close(),这些数据包的正确响应是RST。但如果调用shutdownOutput(),这是一个优雅的关闭进程;首先确认数据包。

编辑:了解更多信息后的另一次尝试:

应用程序协议是,服务器可以随时响应,即使客户端请求仍在传输。因此,假设处于阻塞模式,客户端应该有一个单独的线程从服务器读取数据。一旦客户端从服务器读取到响应,它就需要插入到写线程中,以停止对服务器的进一步写操作。这可以通过简单地关闭()套接字来实现。

在服务器端,如果在读取所有请求数据之前写入响应,然后调用close(),很可能会将RST发送到客户端。显然,如果在接收缓冲区不为空时调用close(),大多数TCP栈会将RST发送到另一端。即使TCP栈不这样做,很可能更多的数据会在close()之后立即到达,无论如何都会触发RST。

当这种情况发生时,客户端很可能无法读取服务器响应,因此出现了问题。

所以服务器不能在响应后立即关闭(),它需要等到客户机收到响应。服务器是怎么知道的?

首先,客户如何知道已收到完整响应?也就是说,响应是如何终止的?如果响应被TCP FIN终止,则服务器必须在响应后通过调用shutdownOutput()发送FIN。如果响应是自终止的,例如通过HTTP Content-Length头,则服务器不需要调用shutdownOutput()。

客户端收到完整的响应后,根据html" target="_blank">协议,它应该立即停止向服务器发送更多数据。这是通过粗暴地切断连接来完成的;协议没有设计出更优雅的方式。FIN或RST都可以。

因此,在写入响应之后,服务器应该继续从客户端读取数据,直到EOF或出现错误。然后它可以关闭()插座。

但是,考虑到恶意/损坏的客户端和网络问题,这一步应该有一个超时。在大多数情况下,几秒钟就足以完成该步骤。

此外,服务器可能不想从客户端读取,因为它不是免费的。服务器可以简单地等待超过超时,然后关闭()。

羊舌涵涤
2023-03-14

如果您可以从Netty获得底层的< code>SocketChannel,我对此不是专家,您可以调用< code>channel.socket()。关闭输出()。

接收缓冲区中的剩余数据会导致Linux(或Java..)用RST标志标记TCP数据包。这会阻止客户端读取数据,因为当客户端开始尝试时,它会发现由于套接字被关闭而出现读取错误。

这个我不懂。TCP保证客户端在获得FIN之前将接收到其套接字接收缓冲区中的所有数据。如果你说的是服务器的套接字接收缓冲区,它将被close()丢弃,客户端进一步发送的尝试将得到一个RST,它变成< code > io exception: connection reset ',因为没有与它关联的连接,因此没有地方放置它。注意是TCP做了所有这些,而不是Java。

但在我看来,如果情况不好,你应该在关闭频道之前阅读整个请求。

您还可以尝试增加套接字接收缓冲区,使其足够大以容纳整个请求。这可确保当您要关闭连接时,客户端不会仍在发送。编辑:我看到请求是兆字节,所以这不起作用。

 类似资料:
  • 问题内容: 我正在努力寻找一种方法,以根据谓词在流的开头跳过某些元素。 像这样: 那相当于Scala 。 问题答案: 这种操作不是s 的预期用例,因为它并入了元素之间的依赖关系。因此,该解决方案可能看起来不太好,因为您必须为谓词引入一个全状态变量: 请注意,与您的示例相比,该条件必须颠倒。 当然,您可以在方法中隐藏令人讨厌的细节: 一个更复杂,但更清洁,可能更有效的方法是深入研究金属,即界面: 可

  • 问题内容: 我是来自C / STL的相对较新的Java程序员,并且正在寻找具有以下特征的类(据我所了解,C std :: deque具有): O(1)在开头/结尾插入/移除的性能 按索引查找的O(1)性能 是可增长的集合(不需要固定的大小范围) 是否有与此等效的Java?我发现Java 1.6 [ArrayDeque]类具有插入/移除和可增长的特性,但是似乎没有按索引查找的方法,除非调用toArr

  • 问题内容: 我需要从一些文本文件中选择一些数字。我可以使用grep选择所需的行,但是不知道如何从行中提取数字。一位同事向我展示了如何使用Perl从bash中做到这一点: 但是,我通常使用Python而不是Perl进行编码。所以我的问题是,我可以用相同的方式使用Python吗?即,我可以将一些东西从bash传递到Python,然后直接将结果传递到stdout吗?…如果有道理。还是在这种情况下Perl

  • 问题内容: 我遇到的问题是,有时我启动的线程在调用它之前就完成了。看来这使我的程序等待不再发生的事情()。如何确保不等待线程完成? 问题答案: 如果您阅读JavaDocs for Thread,它将告诉您 永远不要在Thread对象上使用。您应该使用join()

  • 我是一名普通的C#开发人员,但偶尔会用Java开发应用程序。我想知道是否有与C#async/await相当的Java?简单地说,java等价物是什么:

  • 等价 cljs 的数据结构是在 js 基础之上实现的. 数值类型的数据可以直接判断. 一般通过 (= a b) 判断 a 和 b 的内容是否一致. Collection 类型数据除了 = 函数之外, 还可以使用 identical? 函数判断两个数据的引用是否一致. (identical? {} {}) ; true (identical? {:a 1} {:a 1}) ; false (= {: