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

Как я могу проверить, является ли (TCP) сокет (dis) подключенным в С#?

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

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

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

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

Другое сообщение Пита Дунихо говорит:

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

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

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


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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

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


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

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

Ответ 2

"Если вам нужно определить текущее состояние соединения, сделайте неблокирующий нулевой байтовый вызов. Если вызов возвращается успешно или выдает код ошибки 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, как если бы он действительно отправил что-то. В то время как устройство, о котором идет речь, даже не подключено.

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

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