Как запретить .NET библиотекам отправлять RST-пакет при закрытии - PullRequest
11 голосов
/ 23 августа 2011

Я провожу некоторое тестирование, пытаясь выделить какое-то странное поведение в библиотеках (.NET). Когда я использую Winsock API через C ++ и просто вызываю closesocket(), я вижу, что сторона Windows отправляет пакет FIN / ACK, а удаленная сторона отправляет обратно пакет ACK. Это то, что я бы назвал изящным близким. Однако при программировании на C # я не вижу того, что я бы назвал изящным закрытием.

В C # я открываю свой сокет, а затем, закрывая его, я вижу, что окна отправляют пакет FIN Только при первом вызове Socket.Shutdown(). Однако независимо от того, когда я вызываю Socket.Close() в C #, отправляется пакет RST и соединение прерывается. Это сбивает меня с толку, потому что из того, что я прочитал в режиме онлайн, процесс закрытия TCP должен быть FIN / ACK -> ACK (на самом деле с обеих сторон, но сейчас меня интересует только «моя» сторона); то есть в миксе не должно быть пакета RST. Из того, что я прочитал, очевидно, что пакет RST отправляется только тогда, когда получатель не уверен в состоянии соединения и хочет выйти.

Почему этот пакет RST отправляется при плановом завершении работы в .NET, а не при запланированном завершении работы из Winsock API? Есть ли способ предотвратить передачу пакета RST во время постепенного завершения работы из .NET?

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

Ответы [ 3 ]

5 голосов
/ 20 октября 2014

Чтение .NET документа Socket.Close , вот что я нашел:

Для протоколов, ориентированных на соединение, рекомендуется вызывать Shutdown перед вызовомЗакрыть метод.Это гарантирует, что все данные отправляются и принимаются на подключенном сокете до его закрытия.Если вам нужно вызвать Close без предварительного вызова Shutdown, вы можете убедиться, что данные, поставленные в очередь для исходящей передачи, будут отправлены, установив для параметра DontLinger Socket значение false и указав ненулевой интервал времени ожидания.Затем Close будет блокироваться до тех пор, пока эти данные не будут отправлены или пока не истечет указанное время ожидания.Если для DontLinger задано значение false и указан нулевой интервал времени ожидания, Close освобождает соединение и автоматически отбрасывает исходящие данные в очереди.

, что на самом деле имеет смысл.Если в буфере все еще есть данные (OS one), и вы разрываете соединение или уничтожаете процесс, соединение будет сброшено (более подробная информация в спецификации TCP).

Относительно того, когда отправляется RST, проверьте Руководство по TCP .

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

2 голосов
/ 18 сентября 2015

Следующий код может помешать пакету RST. Это потому, что подождите 60 секунд после отправки пакета FIN.

socket.Close(60);

Описание метода закрытия здесь .

0 голосов
/ 23 августа 2011

Совсем недавно возникла похожая проблема, когда приложение передавало POP3 на сервер Exchange.Когда программа .NET завершилась, она закрылась изящно, и Exchange воспринял диалог POP3 как «прерванный» и откатил его.

Причина этого в том, что, я думаю, TCP RST является односторонним- вам не нужно ждать ответа.Вот что посылает .NET (или, возможно, любая программа после ее завершения). Одно из возможных решений - немного подождать после закрытия сокета и перед выходом из программы:

Thread.Sleep(5000);

Это сработало для проблемы POP3 Iупомянутый ранее;время ожидания привело к корректному завершению соединения, и Exchange больше не прерывал сеанс.

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