2011-04-15 83 views
3

我一直在使用C#编写套接字客户端程序,并且想知道如何检测套接字的另一端何时断开连接,如同拔下网络电缆或硬重置一样。如何检测断开的套接字C#?

我有下面这些功能访问套接字并根据SO质疑hereMSDN 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设备。我在另一个线程中读到,不同的操作系统可能能够在死亡时发送套接字关闭信号。也许Windows Mobile操作系统不这样做?

+0

1字节的消息怎么能有长度为零? :-) – 2011-04-15 17:53:36

+0

很好的问题哈哈。这就是MSDN文章所说的。但是,如果我将尺寸设置为1,那么它就可以工作!我想这很明显,但是通过流发送到服务器端套接字的额外位。我希望Receive()抛出一个异常,而不是如果套接字被关闭,但会阻塞一个,但似乎并不是这种情况... – Zac 2011-04-15 18:04:42

回答

5

如果远程计算机正常断开会话,则方法将返回0字节。你必须检测 知道远端已经断开:

int recv = sock.Receive(data); 
if (recv == 0) 
{ 
    // Remote client has disconnected. 
} 
else 
{ 
    // Remote client has sent data. 
} 

而且,即使有SocketException出现可以识别例外插座断开。

希望这有助于解决您的问题。

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; 
}