如何判断一个套接字已经断开连接?

5
我正在使用C#中的ElSSLSocket。这是一个SecureBlackBox套接字。SecureBlackBox是一个第三方库,用于处理安全套接字。
我可以看到ElSSLSocket对象有一个名为“Socket”的属性,因此底层套接字是普通的.NET套接字。
我的问题是,是否有某种事件可以订阅,以便我可以看到套接字何时不正常断开连接?我有一个客户端服务器连接,经常会断开连接。很难确定是客户端还是服务器,并且很难确定实际原因。
我相当确定应用程序存在一些逻辑问题,即这不是由网络故障或类似问题引起的。
我还应该让您知道,我得到的断开连接是这个错误:
SocketException-远程主机强制关闭了现有的连接
ErrorCode-10054
如果有任何方法可以找到导致这个问题的原因?

请问各位热心的朋友,能否看一下我发的新帖子:https://dev59.com/nE7Sa4cB1Zd3GeqP45ym我决定使用wireshark来查看发生了什么事情。 - peter
3个回答

4
检测半开连接是经典套接字编程场景之一。 Socket.Connected 属性完全无用,Socket.Poll 并不适用于每种情况。最好每隔几秒钟发送一次“心跳”消息。
10054是常见错误之一。它表示连接已丢失(未正常关闭)。这可能是由于远程计算机关闭、远程进程退出,甚至中间路由器重新启动引起的。

这是唯一的方法。我花了几个月的时间研究套接字编程,这就是结论。或者,你可以使用 WCF,所有问题都会迎刃而解。 - NibblyPig
@SLC - 我并不完全认为WCF是万能的。有时候,你会想要简单的Sockets而不是臃肿的框架。 - ChaosPandion
我想要知道的是,客户端和服务器哪一个先断开连接。套接字连接可能会超出范围,即发生未报告但导致异常冒泡的程序错误。有点难以解释。 - peter
我越想越觉得这个错误很可能不是很严重。该过程涉及在客户端和服务器之间同步数据,这可能非常缓慢。可能的原因是“用户”会说“这太慢了,算了”,然后取消该过程。同步过程可以处理这种情况,并在重新启动后继续进行。此外,正如我之前提到的,如果代码中发生特定异常,则可能无法清除套接字。 - peter
另外一个问题是,套接字应该如何关闭?如果一端干净地关闭,我猜另一端的“connected”属性会被设置为false? - peter
套接字可以通过调用“Close”来关闭。它不会引发任何正常的异常,因此每次读取或写入操作失败时都应该这样做。我不知道对“Connected”属性的影响;这个属性本来就是一个设计错误,所有有经验的原生套接字用户(包括我在内)都会忽略它。 - Stephen Cleary

2

虽然这篇文章是用C写的,但你应该能够在C#中做同样的事情:

int dummy;
// since you're just testing if the socket is still open for reading you don't
// want it to block, or remove data from the sockets recv buffer
int ret = recv(sockfd, &dummy, sizeof dummy, MSG_DONTWAIT | MSG_PEEK);

if ( ( ret == -1 && ( errno == EAGAIN || errno == EWOULDBLOCK ) )
      || ret > 0 ) {

    // socket is still open for reading

else if ( ret == 0 ) { 

    // socket went through orderly shutdown and is closed for reading

} else {

    // there is some error and the socket is likely closed
    // check errno

}

假设您认为连接只是部分关闭,并且仍有数据要写入。
int myData = 0xDEADBEEF;
int ret = send(sockfd, myData, sizeof myData, MSG_NOSIGNAL);

这样,如果套接字完全关闭,您的发送操作不会因为 SIGPIPE 而使程序崩溃。相反,调用将只返回 -1 并设置 errnoEPIPE


1

我发现这个方法相当有效:

接收

_socket.Poll(100, SelectMode.SelectRead) && _socket.Available == 0

发送

!_socket.Poll(100, SelectMode.SelectWrite)

@peter - 别忘了 ! - ChaosPandion
你使用的套接字类型和我使用的有区别吗?我正在使用阻塞套接字。另外,当你调用“Poll”时,它实际上在做什么?检查远程套接字是否连接?还是只是检查本地套接字是否按预期工作?也许它对断开连接的反应速度较慢。 - peter
你说不要忘记那个感叹号!但我得到的结果却一样。现在我有点困惑了。如果我这样写:if (!_socket.Poll(100, SelectMode.SelectWrite))这是在告诉我们它正在工作,还是没有工作? - peter
@peter - 你能展示一下你的代码吗?在某些配置中可能无法正常工作。 - ChaosPandion
@ChaosPandion 这个能检测到关闭(非正常)套接字吗(例如杀死服务器进程)? - Royi Namir
显示剩余2条评论

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