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

Как сказать, когда Socket отключен

На стороне клиента мне нужно знать, когда/если соединение сокета было нарушено. Однако свойство Socket.Connected всегда возвращает true, даже после того, как серверная сторона была отключена, и я попытался отправить данные через него. Может кто-нибудь помочь мне выяснить, что происходит здесь. Мне нужно знать, когда сокет был отключен.

        Socket serverSocket = null;
        TcpListener listener = new TcpListener(1530);
        listener.Start();
        listener.BeginAcceptSocket(new AsyncCallback(delegate(IAsyncResult result)
        {
            Debug.WriteLine("ACCEPTING SOCKET CONNECTION");
            TcpListener currentListener = (TcpListener)result.AsyncState;
            serverSocket = currentListener.EndAcceptSocket(result);
        }), listener);


        Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, and it is
        clientSocket.Connect("localhost", 1530);
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be TRUE, and it is

        Thread.Sleep(1000);
        serverSocket.Close();//closing the server socket here
        Thread.Sleep(1000);

        clientSocket.Send(new byte[0]);//sending data should cause the socket to update its Connected property.
        Debug.WriteLine("client socket connected: " + clientSocket.Connected);//should be FALSE, but its always TRUE
4b9b3361

Ответ 1

После некоторого тестирования выяснится, что документация для Socket.Connected неверна или, по крайней мере, вводит в заблуждение. clientSocket.Connected станет ложным только после вызова clientSocket.close(). Я думаю, что это возврат к оригинальному API-интерфейсам C Berkeley sockets и его терминологии. Сокет привязан, когда он имеет локальный адрес, связанный с ним, и сокет подключается, когда он имеет удаленный адрес, связанный с ним. Несмотря на то, что удаленная сторона закрыла соединение, локальный сокет все еще имеет связь и поэтому он все еще "подключен".

Однако, это метод, который работает:

!(socket.Poll(0, SelectMode.SelectRead) && socket.Available == 0)

Он полагается на тот факт, что закрытое соединение будет отмечено как читаемое, даже если данные отсутствуют.

Если вы хотите обнаружить условия, такие как сломанные сетевые кабели или компьютеры, которые внезапно отключены, ситуация немного сложнее. В этих условиях ваш компьютер никогда не получает пакет, указывающий, что сокет закрыт. Необходимо обнаружить, что удаленная сторона исчезла, отправив пакеты и заметив, что ответ не возвращается. Вы можете сделать это на уровне приложения как часть вашего протокола или использовать параметр TCP KeepAlive. Использование TCP Keep Alive от .NET не особенно просто; вам, вероятно, лучше не использовать механизм keep-alive в вашем протоколе (поочередно, вы можете задать отдельный вопрос: "Как включить TCP Keep Alive в .NET и установить интервал сохранения?" ).

Ответ 2

Просто напишите свой сокет как обычно. Вы узнаете, когда оно отключилось из-за исключения, в котором говорится, что ваши данные не могут быть доставлены.

Если вам нечего писать... тогда кто волнуется, если он отключился? Теперь он может быть отключен, но вернитесь, прежде чем он вам понадобится, - зачем беспокоиться о его разрыве, а затем зацикливать повторное подключение до тех пор, пока ссылка не будет восстановлена ​​... особенно, когда вам нечего было сказать?

Если это вас беспокоит, выполните обновление в своем протоколе. Тогда вам будет что сказать каждые 30 секунд или около того.

Ответ 3

Может быть, решение состоит в том, чтобы отправить через него некоторые фиктивные данные и проверить, не истечет ли это время?

Ответ 4

Я рекомендую отключить язык более высокого уровня и исследовать, что происходит на младшем уровне ввода-вывода.

Самый низкий уровень, который я исследовал, был при написании isectd (найти в sourceforge). Используя системный вызов select(), дескриптор закрытого сокета становится готовым к чтению, и когда isectd попытается восстановить recv(), состояние подтверждения разъединения может быть подтверждено.

В качестве решения я рекомендую не писать собственный идентификатор сокета и использовать другое промежуточное программное обеспечение. Там много хороших кандидатов. Не забудьте также рассмотреть простые службы обслуживания очередей.

PS. Я бы предоставил URL-адреса всем вышеперечисленным, но моя репутация (1) не позволяет это.

Ответ 5

метод clientSocket.Send() ожидает, чтобы пакет был либо ack/nack'd?

Если ваш код не летает на следующую строку, а сокет все еще пытается выяснить, что происходит.