我一直在使用C#中的套接字客户端程序,并且想知道如何检测套接字的另一端何时“不正常”地断开连接,就像拔出网络电缆或硬重置一样。
我有以下这些函数来访问套接字并根据SO问题here和此MSDN article,检查断开连接套接字的最佳方法是发送一个1字节的消息长度为0.如果抛出异常且WSAEWOULDBLOCK不是错误代码,则套接字将断开连接。我试过这个但是在硬重置服务器连接后,客户端将调用Send(new byte[1], 0, 0, SocketFlags.None)
并成功返回,然后Receive()
命令返回WSAEWOULDBLOCK错误。
是什么?
以下是我的代码。 _socket
设置为非阻止模式:
private int nonBlockRecv(byte[] recvBytes, int offset, int size, SocketFlags sf)
{
int bytesRecv = 0;
while (true)
{
try
{
nonBlockSend(new byte[1], 0, 0, sf);
bytesRecv = _socket.Receive(recvBytes, offset, size, sf);
break;
}
catch (SocketException excp)
{
if (excp.ErrorCode != 10035) // WSAEWOULDBLOCK
throw excp;
}
}
return bytesRecv;
}
private int nonBlockSend(byte[] sendBytes, int offset, int size, SocketFlags sf)
{
int bytesSent = 0;
while (true)
{
try
{
_socket.Send(sendBytes, offset, size, sf);
break;
}
catch (SocketException excp)
{
if (excp.ErrorCode != 10035) // WSAEWOULDBLOCK
throw excp;
}
}
return bytesSent;
}
编辑:这可能是有益的,但服务器是Windows Mobile设备。我在另一个线程中读到,不同的OS可能会在它们死亡时发送套接字关闭信号。也许Windows Mobile OS不会这样做??
答案 0 :(得分:6)
如果远程计算机正常断开会话,则
Socket.Receive()
方法将以0字节返回。你必须检测到它
要知道远程端已断开连接:
int recv = sock.Receive(data);
if (recv == 0)
{
// Remote client has disconnected.
}
else
{
// Remote client has sent data.
}
此外,即使出现SocketException
,您也可以识别套接字断开的异常。
希望这有助于解决您的问题。
答案 1 :(得分:0)
我知道这已经很晚了,但我想出了一个狡猾的解决方案。
我不得不与第三方软件进行通信,该软件期望在发送的每个命令上都有回车符,否则会忽略它。
在主要阶段,我的客户端套接字处于循环中,接收来自第三方软件的响应。我的解决方案并不理想,但基本前提是我在套接字上设置接收超时,以便循环尝试读取5秒然后落入catch,然后再循环。在每次接收之前,我调用我自己的isconnected方法,它执行一个没有回车的小写,所以它被第三方软件忽略,但如果网络丢失,它将给我一个可靠的失败。如果写入失败,我所做的就是抛出一个LostConnectionException并在外部处理它。
如果你正在编写服务器和客户端,你可以很容易地想出一个另一个忽略的checkdigit。
这可能不完美但对我来说可靠。
while (numberOfBytesRead == 0)
{
try
{
IsConnected();
_socket.ReceiveTimeout = 5000;
numberOfBytesRead = _socket.Receive(myReadBuffer, 0, myReadBuffer.Length, SocketFlags.None);
}
catch (Exception e)
{
if (e.GetType() == typeof (LostConnection))
{
Status = SocketStatus.offline;
throw;
}
}
}
并且isconnected方法看起来像这样
public bool IsConnected(Socket s)
{
try
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("test");
s.Send(buffer, 0, buffer.Length, SocketFlags.None);
}
catch (Exception)
{
throw new LostConnection();
}
return s.Connected;
}