Как я могу проверить, подключен ли (dis) сокет (TCP) в C #? - PullRequest
33 голосов
/ 05 февраля 2009

Как мне проверить (TCP) сокет, чтобы узнать, подключен ли он?

Я прочитал о свойстве Socket.Connected в MSDN , но он говорит, что показывает только состояние в соответствии с последним вводом / выводом. Это бесполезно для меня, так как я хочу сделать это перед попыткой чтения из сокета. Раздел замечаний также отмечает, что:

Если вам нужно определить текущий состояние соединения, сделать Неблокируемый, нулевой байт Отправить звонок. Если звонок успешно завершен или выдает код ошибки WAEWOULDBLOCK (10035), то розетка еще связано; в противном случае сокета нет больше подключен.

Пример на той же странице показывает, как это сделать. (1) Но сообщение Иана Гриффитса говорит, что я должен прочитать из сокета , не отправить через него.

Еще одна публикация Пита Дунихо говорит:

... после того, как вы позвонили Shutdown(), Звоните Receive(), пока он не вернется 0 (при условии, что удаленная конечная точка не на самом деле собираюсь отправить вам что-нибудь, это произойдет, как только пульт конечная точка получила все ваши данные). Если вы этого не сделаете, у вас есть нет уверенности в том, что удаленная конечная точка фактически получил все данные вы отправили, даже используя затяжной розетка.

Я не совсем понимаю его заявление о вызове Receive(), чтобы убедиться, что удаленная конечная точка фактически получила все данные, которые я отправил . (Блокирует ли получение сокеты, пока буфер отправки не опустеет?)

Меня смущают разные предложенные методы. Не могли бы вы объяснить их?


(1) Интересно, почему пример для свойства Socket.Connected выделяет 1-байтовый массив, даже если он вызывает Send с длиной 0?

Ответы [ 4 ]

21 голосов
/ 05 февраля 2009

Смерть сокета меняет свое поведение несколькими способами, поэтому оба метода действительны:)

С помощью обоих методов вы фактически проверяете те части поведения сокета, которые меняются после отключения.

Я не совсем понимаю его заявление о вызове Receive (), чтобы убедиться, что удаленная конечная точка действительно получила все отправленные мной данные. (Блокирует ли получение сокеты, пока буфер отправки не опустеет?)

TCP - это надежный протокол, который означает, что каждый отправленный вами пакет должен быть подтвержден. Подтверждение подразумевает отправку пакетов с установленным битом ACK. Эти пакеты могут содержать или не содержать дополнительные (полезные данные) данные.

Когда сокет подключен, Receive() будет блокироваться, пока сокет не получит пакет с непустой полезной нагрузкой. Но когда сокет отключен, Receive() вернется, как только прибудет последний пакет ACK.

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

Пример на той же странице показывает, как это сделать. (Интересно, почему он выделяет 1-байтовый массив, хотя и вызывает Send с длиной 0?) Но в сообщении Иана Гриффитса говорится, что я должен читать из сокета, а не отправлять через него.

При send() в сокете вы фактически пытаетесь добавить некоторые данные в конец очереди сокета. Если в буфере осталось место, то ваш Send() мгновенно возвращается, если нет, блоки Send(), пока не будет места.

Когда сокет находится в отключенном состоянии, стек TCP/IP предотвращает все дальнейшие операции с буфером, поэтому Send() возвращает ошибку.

Send() реализует базовую проверку указателя, это означает, что она не работает, когда ей передается указатель NULL. Возможно, вы можете передать любую ненулевую константу в качестве указателя, но вам лучше выделить 1 байт, а не делать константу up - на всякий случай.


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

Что касается меня, я бы предпочел Receive(), так как это то, что вы обычно запускаете в цикле и ждете. Вы получаете ненулевое значение от Receive(), вы обрабатываете данные; Вы получаете ноль, вы обрабатываете отключение.

4 голосов
/ 30 августа 2010

"Если вам нужно определить текущее состояние соединения, выполните неблокирующий нулевой байт отправляющий вызов. Если вызов успешно завершен или выдает код ошибки WAEWOULDBLOCK (10035), то сокет все еще подключен; в противном случае розетка больше не подключена. " - к сожалению, это даже не работает!

mySocket.Blocking = false;
byte[] buffer = new byte[1];
int iSent = mySocket.Send(buffer, 0, SocketFlags.None);
bConnected = mySocket.Connected;

bConnected всегда заканчивается как true, и вызов всегда возвращается успешно, даже если кабель Ethernet был отключен.

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

buffer[0] = 0xff ;
int iSent = mySocket.Send(buffer, 1, SocketFlags.None);

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

1 голос
/ 04 июля 2012

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

Сообщение @PeteDuniho не об установлении состояния соединения, а о прекращении соединения таким образом, чтобы вы знали, когда узел получил все ваши данные.

(блокирует ли получение сокеты, пока буфер отправки не пуст?)

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

1 голос
/ 05 февраля 2009

Как правило, можно использовать метод Socket.Select для определения состояния набора сокетов (Socket.Poll для одного сокета).

Оба эти метода позволяют запрашивать состояние сокета. Теперь, предположив, что вы отследили, что сокет подключен в первую очередь, вы обычно вызываете Select / Poll для сокета перед попыткой чтения. Если Select / Poll указывает, что сокет доступен для чтения, это говорит о том, что:

  • Либо в сокете имеются данные, доступные для чтения, в этом случае функция Receive возвращает данные, доступные для чтения.
  • Сокет сокета был закрыт, и в этом случае при вызове Receive 0 байты будут возвращены немедленно (т. Е. Если Select / Poll указывает, что сокет доступен для чтения, и вы вызываете Receive, но он сразу возвращается с 0 байтами, тогда вы знаете, что соединение было закрыто, сброшено или прервано.

Лично я никогда не использовал опрос - я всегда использовал Select, но MSDN, похоже, предполагает, что опрос почти такой же, как Select, но для отдельных сокетов.

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

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