2009-09-07 85 views
26

我正在玩TcpClient,我試圖弄清楚如何使連接屬性在斷開連接時發生錯誤。如何檢查TcpClient連接是否關閉?

我試着做

NetworkStream ns = client.GetStream(); 
ns.Write(new byte[1], 0, 0); 

但它仍然不會告訴我,如果TcpClient的斷開。你會如何使用TcpClient來解決這個問題?

回答

7

據我所知/記住,沒有辦法測試套接字是否連接,而不是讀取或寫入它。

我還沒有使用過TcpClient,但是如果遠程端已經正常關閉,Socket類將從調用返回0來讀取。 如果遠端沒有正常關機[我認爲]你會得到一個超時異常,不記得類型抱歉。

使用像'if(socket.Connected) { socket.Write(...) }'這樣的代碼創建競爭條件。你最好只是調用socket.Write並處理異常和/或斷開連接。

+0

是的。套接字層應使用異常進行管理。拋出的IOException將內部異常設置爲SocketException,其中包含遠程檢測超時或關閉套接字所需的所有信息。 – Luca 2010-08-26 09:14:52

-1

試試這個,它爲我工作

private void timer1_Tick(object sender, EventArgs e) 
    { 
     if (client.Client.Poll(0, SelectMode.SelectRead)) 
      { 
       if (!client.Connected) sConnected = false; 
       else 
       { 
        byte[] b = new byte[1]; 
        try 
        { 
         if (client.Client.Receive(b, SocketFlags.Peek) == 0) 
         { 
          // Client disconnected 
          sConnected = false; 
         } 
        } 
        catch { sConnected = false; } 
       } 
      } 
     if (!sConnected) 
     { 
      //--Basically what you want to do afterwards 
      timer1.Stop(); 
      client.Close(); 
      ReConnect(); 
     } 

    } 

我使用定時器,因爲我想在固定時間間隔 檢查連接狀態,並且不能聽代碼的循環[我覺得這是減緩sending-接收過程]

+0

偶然發現了這個答案,只是好奇爲什麼它被拒絕投票? – nagates 2014-11-05 17:10:53

+1

對我不起作用,對於downvoter我也不想 – sotn0r 2015-01-16 00:00:21

33

我不會推薦你嘗試寫測試套接字。並且不要在.NET的Connected屬性上傳遞。

如果你想知道,如果遠程端點仍處於活動狀態,您可以使用TcpConnectionInformation:

TcpClient client = new TcpClient(host, port); 

IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties(); 
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray(); 

if (tcpConnections != null && tcpConnections.Length > 0) 
{ 
    TcpState stateOfConnection = tcpConnections.First().State; 
    if (stateOfConnection == TcpState.Established) 
    { 
     // Connection is OK 
    } 
    else 
    { 
     // No active tcp Connection to hostName:port 
    } 

} 
client.Close(); 

另請參見:
TcpConnectionInformation MSDN上
IPGlobalProperties MSDN上
說明TcpState狀態
Netstat Wikipedia


這裏它是作爲TcpClient的擴展方法。

public static TcpState GetState(this TcpClient tcpClient) 
{ 
    var foo = IPGlobalProperties.GetIPGlobalProperties() 
    .GetActiveTcpConnections() 
    .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)); 
    return foo != null ? foo.State : TcpState.Unknown; 
} 
+2

這是一個很棒的答案。您可以改進它的唯一方法是將測試作爲返回套接字狀態的Socket擴展方法呈現。 – 2014-08-12 09:45:39

+0

不錯的一個。我真的很想知道是否有更快的方法來做到這一點 – 2015-08-04 04:17:00

+0

謝謝!你的答案是第一個爲我工作的答案。我嘗試過使用client.Client.Poll的各種答案,但他們沒有工作。 – 2016-11-21 15:27:21

2

@ uriel的答案對我很好,但我需要用C++/CLI編寫代碼,這並不是完全無關緊要的。這裏是(大致相當的)C++/CLI代碼,並添加了一些健壯性檢查以實現良好的度量。

using namespace System::Net::Sockets; 
using namespace System::Net::NetworkInformation; 

TcpState GetTcpConnectionState(TcpClient^tcpClient) 
{ 
    TcpState tcpState = TcpState::Unknown; 

    if (tcpClient != nullptr) 
    { 
     // Get all active TCP connections 
     IPGlobalProperties^ipProperties = IPGlobalProperties::GetIPGlobalProperties(); 
     array<TcpConnectionInformation^>^tcpConnections = ipProperties->GetActiveTcpConnections(); 

     if ((tcpConnections != nullptr) && (tcpConnections->Length > 0)) 
     { 
      // Get the end points of the TCP connection in question 
      EndPoint^localEndPoint = tcpClient->Client->LocalEndPoint; 
      EndPoint^remoteEndPoint = tcpClient->Client->RemoteEndPoint; 

      // Run through all active TCP connections to locate TCP connection in question 
      for (int i = 0; i < tcpConnections->Length; i++) 
      { 
       if ((tcpConnections[i]->LocalEndPoint->Equals(localEndPoint)) && (tcpConnections[i]->RemoteEndPoint->Equals(remoteEndPoint))) 
       { 
        // Found active TCP connection in question 
        tcpState = tcpConnections[i]->State; 
        break; 
       } 
      } 
     } 
    } 

    return tcpState; 
} 

bool TcpConnected(TcpClient^tcpClient) 
{ 
    bool bTcpConnected = false; 

    if (tcpClient != nullptr) 
    { 
     if (GetTcpConnectionState(tcpClient) == TcpState::Established) 
     { 
      bTcpConnected = true; 
     } 
    } 
    return bTcpConnected; 
} 

希望這會幫助某人。

2

我已經創建了這個函數,併爲我檢查客戶端是否仍然與服務器連接。

/// <summary> 
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER. 
/// </summary> 
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns> 
public bool isClientConnected() 
{ 
    IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties(); 

    TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections(); 

    foreach (TcpConnectionInformation c in tcpConnections) 
    { 
     TcpState stateOfConnection = c.State; 

     if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint)) 
     { 
      if (stateOfConnection == TcpState.Established) 
      { 
       return true; 
      } 
      else 
      { 
       return false; 
      } 

     } 

    } 

    return false; 


} 
+0

謝謝,它解決了我的問題。 – Pratikk 2015-12-01 11:55:10

0

在我的情況,我被髮送一些命令到服務器(在同一計算機上的虛擬機上運行),並等待響應。但是,如果服務器在等待時意外停止,我沒有收到任何通知。我嘗試了其他海報提出的可能性,但都沒有工作(它總是說服務器仍然連接)。對於我來說,這是工作的唯一的事情就是寫0字節流:

var client = new TcpClient(); 
//... open the client 

var stream = client.GetStream(); 

//... send something to the client 

byte[] empty = { 0 }; 
//wait for response from server 
while (client.Available == 0) 
{ 
    //throws a SocketException if the connection is closed by the server 
    stream.Write(empty, 0, 0); 
    Thread.Sleep(10); 
} 
1

彼得Wone的解決方案和烏列是非常好的。但是您還需要檢查遠程端點,因爲您可以有多個到您的本地端點的開放連接。

public static TcpState GetState(this TcpClient tcpClient) 
    { 
     var foo = IPGlobalProperties.GetIPGlobalProperties() 
      .GetActiveTcpConnections() 
      .SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint) 
          && x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint) 
     ); 

     return foo != null ? foo.State : TcpState.Unknown; 
    }