Как узнать, когда сокет был отключен - PullRequest
16 голосов
/ 31 марта 2010

На стороне клиента мне нужно знать, когда / было ли разорвано мое сокетное соединение. Однако свойство 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

Ответы [ 5 ]

10 голосов
/ 01 апреля 2010

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

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

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

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

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

4 голосов
/ 01 апреля 2010

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

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

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

3 голосов
/ 01 апреля 2010

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

2 голосов
/ 01 апреля 2010

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

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

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

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

0 голосов
/ 31 марта 2010

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

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

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