C#和Java以及Java和C#的客户端\服务器对-当客户端(套接字)关闭时优雅地断开连接

3
这可能更多是讨论而不是问题。
背景: 我有两对服务器/客户端,一对用Java编写,另一对用C#编写。这两对都在做同样的事情。当我使用Java\Java和C#\C#组合时没有问题。我也想让Java\C#和C#\Java的组合也能正常工作。I\O没有问题,我使用字节数组表示XML格式化字符串。我必须使用TCP。
我需要注意优雅地断开连接,在Java中没有这样的东西。当你关闭客户端套接字时,服务器端套接字仍处于被动关闭状态——因此处理此套接字的服务器线程仍然活着,如果有很多客户端,我可能会遇到数千个不必要的线程。在C#中,只需调用TcpClient.Available即可确定缓冲区中是否有数据或客户端是否已关闭(SocketException)。在Java中,我可以考虑两种方法:
1.您必须向套接字的底层流写入一些内容,以真正测试另一侧是否仍然打开。 2.在关闭它之前,您必须让另一方知道您正在关闭连接的一侧。我已经实现了这个,关闭客户端套接字之前,我发送一个包含0x04字节(传输结束)的数据包到服务器,服务器通过关闭套接字的服务器端来响应该字节。
不幸的是,当涉及到C#\Java和Java\C#客户端\服务器对时,这两种方法都让我陷入了两难境地。如果我希望这些对能够相互通信,我将不得不添加代码以向C#客户端发送0x04字节,并且当然还要处理C#服务器中的代码,这有点过于繁琐。但我可以忍受不必要的网络流量,主要问题是这个C#代码是核心通信库的一部分,除非绝对必要,否则我不想去碰它。
问题: 在Java中是否有其他方法来优雅地断开连接,而不需要写入套接字的底层流并检查结果,因此我不必在C#代码中处理它?在使用的库方面,我有自由,我不必仅使用Java SE\EE。

旧版的java.io - Socket和ServerSocket。通信没有问题,我能够自由地在客户端和服务器之间发送消息。我只是想知道,在C#代码中是否也需要处理优雅的断开连接,以便让这些混合的对一起工作。 - Jan Hruby
1
嗯,我以为如果在关闭的套接字上调用getOutput/InputStream会抛出SocketException。你有设置SocketTimeout值吗? - Fildor
我无法使用超时,因为我根本不知道客户端的某些数据何时到达。它可能长时间处于休眠状态,然后发送一些内容。这是原始的C#服务器/客户端对之间的约定,我正在将其重写为Java,并且不能(也不应该)更改。 - Jan Hruby
这导致了我的最初困境 - 如果我手动处理另一部分,并且我希望服务器\客户端的混合配对工作,我还必须修改C#代码,否则它会将0x04字节处理为常规消息,而我不想要那样。 - Jan Hruby
1
我还记得我曾经通过设置超时时间和循环读取的方式来完成这个任务,忽略了SocketTimeoutException。这种方法可以在socket实例中定期获取输出流,并在对等方关闭socket时由于SocketException失败时做出反应。 - Fildor
显示剩余3条评论
2个回答

2
我在这个“优雅断开连接”主题上在这个答案中给出了(我认为是)简明的解释,希望你会觉得有用。
请记住,双方必须使用相同的优雅断开模式。我发现自己尝试优雅地断开客户端套接字,但服务器仍在发送数据(没有关闭自己的一侧),导致一个无限循环...

是的,我也遇到了这个问题,就像你所说的那样,我不得不在C#和Java两种语言中都实现优雅断开连接。在C#中,可以获取系统上运行的所有线程列表,从中提取应该终止的线程并关闭它们。但这只解决了C#服务器的情况,而且有点像用锤子打蚊子。 - Jan Hruby
1
@JanHruby 对我来说,你实现的方案(发送0x4指示传输结束)听起来就像优雅断开连接的概念,只是你应该使用“FIN”TCP信号而不是发送消息。你可以通过在客户端套接字上调用shutdown(SD_SEND)来发送此FIN。它通过读操作返回0字节来在服务器上检测到,这意味着服务器套接字可以安全关闭,平稳地终止您的线程。 虽然我通常会在一个线程中处理所有客户端套接字,并使用select来知道哪个套接字有活动。 - Matthieu

0

答案显而易见。C# 中也没有优雅的断开连接,它关乎 TCP 协议。因此与 Java 一样存在同样的问题,只有一个细微的区别,如果你通过 NetworkStream 发送 0 字节,然后检查 TcpClient.Connected 状态,则某些情况下可以解决问题。然而,根据我在互联网上发现的信息,这既不可靠也不是 C# 中测试连接的首选方式。当然,在我的 C# 库中已经使用了它。在Java中,你根本不能使用这个方法。

因此,我的解决方案是客户端断开连接时向服务器发送“传输结束”数据包,这是可靠的,我已经在 C# 库中引入了它。现在,我只是担心第一个 bug 的出现......

最后一点,我还必须实现一种机制,用于收集为崩溃的客户端处理线程。如果你在做类似的事情,请记住,没有一个客户端能够按预期结束:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接