Async TCP System.Net.Socket send (Begin / End Send) фактически ничего не отправляет - PullRequest
3 голосов
/ 07 сентября 2011

Справочная информация:

Я использую TCP-сервер на одной машине с несколькими клиентами на разных машинах, подключающихся через TCP, и я наблюдаю за сетевым трафиком с помощью Wireshark, а также с ведением журналаиз моего серверного приложения и через tracelistener System.Diagnostics на System.Net.Sockets в подробном режиме.

Проблема:

При попытке просмотреть мои журналы из-за некоторых неожиданных отключений я вижу очень странное поведение.Согласно журналам приложений сервера и журналам вывода System.Diagnostic, мой сервер отправляет 4-байтовый пакет клиенту, используя начало / конец отправки.BeginSend завершается, и EndSend также завершает, говоря, что он успешно отправил 4-байтовый пакет.

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

Кроме того, существуетнеожиданное отключение, которое происходит вскоре после предположительно успешной отправки пакета (~ 30 секунд спустя), что вызвано SocketException в методе EndReceive моего сервера.Но в промежутке между попыткой отправки с сервера сервер подтверждает получение пакетов от клиента, поэтому я знаю, что соединение все еще активно.

Кто-нибудь там испытывал подобное или знает оошибка или что-то, что может быть причиной этого?

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

Примеры журналов

Из моего серверного приложения:

    2011-09-07 10:41:38,812 Attempting to send Packet (BeginSend - 4 bytes)
    2011-09-07 10:41:38,812 Sent Packet (EndSend - 4 bytes)

Из журнала трассировки System.Diagnostics:

System.Net.Sockets Verbose: 0 : [4376] Socket#19699911::BeginSend()
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [0980] Data from Socket#19699911::PostCompletion
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [0980] 00000000 : 02 04 00 00                                     : ....
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Socket#19699911::EndSend(OverlappedAsyncResult#44209720)
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Exiting Socket#19699911::EndSend()   -> 4#4
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Exiting Socket#19699911::BeginSend()     -> OverlappedAsyncResult#44209720
    DateTime=2011-09-07T17:41:38.8125000Z

Я бы тоже вставил журналы Wireshark, но по сути в это время на интерфейсе для этого устройства ничего не регистрируется, кромедля пакетов, поступающих от клиента, и соответствующих подтверждений от сервера.

Редактировать: По запросуКод для отправки (сокращен из-за нехватки места и других причин).Довольно просто, не так много, что может пойти не так.

В моем методе BeginSend:

socket.BeginSend(data, 0, data.Length, SocketFlags.None, EndSend, state);

В моем методе EndSend:

bytesSent = socket.EndSend(ar);

Примечание: Это не мое первое родео, как они говорят ... Я пишу серверы и клиенты, использующие сокеты TCP, в течение последних 15 лет, и никогда раньше не сталкивался с этим.

Кроме того, версия .NETя использую 4,0 ... если это имеет какое-либо отношение.

Справка!

Ответы [ 4 ]

0 голосов
/ 03 сентября 2013

Ну, этот вопрос был давным-давно, так что вы, вероятно, пошли дальше ... в случае, если у кого-то есть такая же проблема, вы можете проверить, может ли Windows * Memory Pressure Protection срабатывать Это приведет к тому, что пакеты будут отброшены при наличии нескольких одновременных подключений, что вы и видите.

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

0 голосов
/ 08 сентября 2011

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

Это утверждение неверно. Тот факт, что вы успешно записываете данные в сокет, не означает, что данные были получены клиентом или даже покинули вашу машину. Это просто означает, что он был успешно записан во внутренние буферы TCP / IP. TCP / IP отправит эти данные в таком количестве или в нескольких блоках / кадрах, которые он сочтет нужными. Это особенно верно, если данные, которые вы отправляете, малы, TCP / IP откладывает попытку объединения дополнительных данных в кадр.

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

0 голосов
/ 08 сентября 2011

Если можно игнорировать его ограничения, можно ли будет переписать приложение, чтобы использовать TcpClient вместо Socket?Если ваше приложение связано с TCP / IP в любом случае, по крайней мере для этого конкретного сокета, вы можете также использовать абстракцию - это может помочь.Кроме того, вы можете попробовать использовать перегрузку EndSend(IAsyncResult, SocketError), чтобы увидеть, содержит ли объект SocketError что-нибудь полезное.

Если ни одна из этих программных настроек не помогает, я должен согласиться, чтопроблема должна быть ниже уровня программного обеспечения .NET, т. е. в программном (или аппаратном) брандмауэре, антивирусе и т. д.

0 голосов
/ 08 сентября 2011

Одна проблема, с которой я столкнулся при программировании сокетов в .NET, была связана со сборкой мусора.Мой код создавал сокет и назначал локальную переменную в моем методе вместо назначения переменной-члену.Затем сокет был собран сборщиком мусора, в результате чего SocketException.По-видимому, выполнения BeginSend было недостаточно для хранения ссылки на этот сокет.

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

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