Подтвердить что ты не робот

Как проверить, закрыто ли соединение TcpClient?

Я играю с TcpClient, и я пытаюсь понять, как сделать свойство Connected ложным при отключении соединения.

Я пробовал делать

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

Но он все равно не покажет мне, отключен ли TcpClient. Как бы вы это сделали, используя TcpClient?

4b9b3361

Ответ 1

Я бы не рекомендовал вам попробовать писать только для тестирования сокета. И не ретранслируйте также свойство .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

Насколько я знаю/помню, нет способа проверить, подключен ли сокет, кроме чтения или записи на него.

Я вообще не использовал TcpClient, но класс Socket вернет 0 из вызова Read, если удаленный конец был отключен изящно. Если удаленный конец не выключается изящно [я думаю], вы получаете исключение тайм-аута, не можете вспомнить тип извинения.

Использование кода типа 'if(socket.Connected) { socket.Write(...) } создает условие гонки. Вам лучше просто вызвать socket.Write и обработать исключения и/или отключения.

Ответ 3

Ответ @uriel отлично работает для меня, но мне нужно было его закодировать в С++/CLI, что было не совсем тривиально. Вот (примерно эквивалентный) код С++/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;
}

Надеюсь, это поможет кому-то.

Ответ 4

Я создал эту функцию и работал у меня, чтобы проверить, все ли клиент подключен к серверу.

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


}

Ответ 5

Решение Peter Wone и uriel очень приятно. Но вам также нужно проверить удаленную конечную точку, так как вы можете иметь несколько открытых подключений к вашей локальной конечной точке.

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

Ответ 6

В моем случае я отправлял некоторую команду на сервер (работающий на виртуальной машине на том же компьютере) и ожидая ответа. Однако, если сервер неожиданно остановился во время ожидания, я не получил никаких уведомлений. Я пробовал возможности, предлагаемые другими плакатами, но и не работал (он всегда говорил, что сервер все еще подключен). Для меня единственное, что работает, это написать 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);
}

Ответ 7

Попробуй, это работает для меня

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

    }

Я использовал Таймер, потому что я хотел проверить состояние соединения на регулярном интервале а не в LOOP с кодом прослушивания [Я чувствовал, что это замедляет процесс отправки)