2011-04-15 71 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; 
}