有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Nettysocket。shutdownOutput()等效于避免TCP RST?

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

用例是:

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

问题是:

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

对于直接的Javasocket,我相信解决方案是调用socket。关闭前关闭输出()。在Netty中有没有一个等价的函数

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

供参考:http://cs.baylor.edu/~donahoo/practical/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()等效的消息

解决方案是从客户端读取所有数据(但您永远无法确定客户端何时会完全停止发送,尤其是在恶意客户端的情况下),或者只是在发送响应后关闭连接之前等待(请参阅来自Unreputable的回答)


共 (2) 个答案

  1. # 1 楼答案

    如果您可以从Netty获得底层的SocketChannel,而我对这方面不是专家,那么您可以调用channel.socket().shutdownOutput().

    Remaining data in the receive buffer causes Linux (or Java..) to flag the TCP packets with the RST flag. This prevents the client from reading the data since when it gets around to trying it finds it has a read error due to the socket being closed.

    我不明白。TCP保证客户端在获得FIN之前将接收其套接字接收缓冲区中的所有数据。如果您谈论的是服务器的套接字接收缓冲区,它将被close()丢弃,客户端进一步尝试发送将得到一个RST,它将成为一个IOException:连接重置,因为没有与之关联的连接,因此无处放置它。注意,这一切都是由TCP完成的,而不是Java

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

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

  2. # 2 楼答案

    您可以尝试以下操作:在服务器写入错误消息后,等待500毫秒,然后关闭()。查看客户端现在是否可以接收错误消息

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


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

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

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

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

    因此,服务器无法在响应后立即关闭(),它需要等待客户端收到响应。服务器如何知道这一点

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

    根据协议,客户端收到完整响应后,应立即停止向服务器发送更多数据。这是通过粗略地切断连接来实现的;协议没有设计出更优雅的方式。鱼翅或鱼翅都可以

    因此,服务器在写入响应后,应该继续从客户端读取,直到EOF或出错。然后它可以关闭套接字

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

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