web-dev-qa-db-ja.com

TcpClient接続が閉じているかどうかを確認する方法

TcpClientをいじって、接続が切断されたときにConnectedプロパティをfalseに設定する方法を理解しようとしています。

やってみた

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

ただし、TcpClientが切断されている場合は、まだ表示されません。 TcpClientを使用してこれをどのように行いますか?

29
Superdumbell

ソケットをテストするためだけに書き込むことはお勧めしません。また、.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 on 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;
}
41
uriel

私が知っている/覚えている限り、ソケットが接続されているかどうかをテストする方法は、読み取りまたは書き込み以外にはありません。

私はTcpClientをまったく使用していませんが、リモートエンドが正常にシャットダウンされている場合、SocketクラスはReadの呼び出しから0を返します。リモートエンドが正常にシャットダウンしない場合[私は思います]タイムアウト例外が発生し、タイプを思い出せません。

'if(socket.Connected) { socket.Write(...) }のようなコードを使用すると、競合状態が発生します。あなたは単にsocket.Writeを呼び出して例外や切断を処理する方がいいです。

7
Kepboy

私はこの関数を作成し、クライアントがサーバーに接続されているかどうかを確認するために働いています。

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


}
2
user391318

ピーターワインとウリエルの解決策は非常に素晴らしいです。ただし、ローカルエンドポイントへの接続が複数開いている可能性があるため、リモートエンドポイントも確認する必要があります。

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

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

うまくいけば、これは誰かを助けるでしょう。

1
Rawk

私の場合、サーバー(同じコンピューター上の仮想マシンで実行中)にコマンドを送信して、応答を待っていました。ただし、待機中にサーバーが予期せず停止した場合、通知はありませんでした。他の投稿者が提案した可能性を試してみましたが、どちらも機能しませんでした(サーバーはまだ接続されていると常に言っていました)。私にとって、機能しているのはストリームに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);
}
0
LionAM