Как обнаружить отключенный сокет C #? - PullRequest
4 голосов
/ 15 апреля 2011

Я работал над клиентской программой на сокете в C # и мне интересно, как определить, когда другой конец сокета отключился сам по себе, «как изящно», как при отключении сетевого кабеля или принудительном сбросе.

У меня есть эти функции ниже для доступа к сокету и в соответствии с вопросом SO здесь и этой статьей MSDN , лучший способ проверить наличие отключенного сокета - отправить 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 этого не делает ??

Ответы [ 2 ]

6 голосов
/ 15 апреля 2011

Если удаленный компьютер корректно отключает сеанс, Socket.Receive() метод вернется с 0 байтами. Вы должны обнаружить, что знать, что удаленный конец отключился:

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

Кроме того, даже если SocketException возникает, вы можете идентифицировать исключение для разъединения сокета.

Надеюсь, это поможет решить вашу проблему.

1 голос
/ 30 мая 2013

Я знаю, что уже поздно, но я нашел хитрое решение для этого.

Мне приходилось связываться с сторонним программным обеспечением, которое ожидало возврат каретки при каждой отправленной команде, в противном случае оно игнорировалось.

Во время основной фазы мой клиентский сокет был в цикле, получая ответы от стороннего программного обеспечения. Мое решение не идеальное, но основная предпосылка состоит в том, что я помещаю тайм-аут приема в сокет, чтобы цикл попытался прочитать в течение 5 секунд, затем попал в ловушку, а затем повторил цикл. Перед каждым получением я вызываю свой собственный метод isconnected, который выполняет небольшую запись без возврата каретки, поэтому он игнорируется сторонним программным обеспечением, но при этом дает мне надежный сигнал сбоя в случае сбоя сети. Все, что я делаю в случае неудачной записи, - это генерирую исключение LostConnectionException и обрабатываю его извне.

Если вы пишете как сервер, так и клиент, вы можете легко придумать какой-нибудь контрольный символ, который другой игнорирует.

Это может быть не идеально, но это надежно для меня.

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...