Отказ от TCP-соединения до его принятия? - PullRequest
11 голосов
/ 18 ноября 2009

В winsock есть 3 разные версии accept. Помимо базового accept, который существует для соответствия стандарту, есть также AcceptEx, который кажется наиболее продвинутой версией (из-за перекрывающихся возможностей io), и WSAAccept. Последний поддерживает условный обратный вызов, который, насколько я понимаю, позволяет отклонять запросы на подключение до того, как они будут приняты (когда включена опция SO_CONDITIONAL_ACCEPT). Ни одна из других версий не поддерживает эту функцию.

Поскольку я предпочитаю использовать AcceptEx с перекрывающимся вводом-выводом, мне интересно, почему эта функциональность доступна только в более простой версии?

Я недостаточно знаю о внутренней работе TCP, чтобы сказать, есть ли какая-либо разница между отклонением соединения до его принятия и отключением сокета сразу после установления соединения? И если есть, есть ли способ имитировать функциональность WSAAccept с AcceptEx?

Может кто-нибудь пролить свет на эту проблему?

Ответы [ 2 ]

17 голосов
/ 18 ноября 2009

Когда соединение установлено, удаленный конец отправляет пакет с установленным флагом SYN . Сервер отвечает пакетом SYN, ACK , и после этого удаленный конец отправляет пакет ACK , который может уже содержать данные.

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

Второй закрывает соединение, как только оно было сформировано. На уровне TCP нет способа немедленно закрыть соединение в обоих направлениях - единственное, что вы можете сказать, это то, что «я не собираюсь больше отправлять данные». Это происходит так, что когда первоначальный обмен SYN , SYN, ACK , ACK завершен, сервер отправляет пакет FIN на удаленный конец. В большинстве случаев, сообщая другому концу с FIN , что «Я не собираюсь больше отправлять данные», заставляет другой конец также закрывать соединение и отправлять свой собственный пакет FIN, Соединение, разорванное таким образом, ничем не отличается от обычного соединения, по которому по какой-либо причине данные не отправлялись. Это означает, что отслеживание нормального состояния для соединений TCP и длительное состояние закрытия будут сохраняться, как и для обычных соединений.

Теперь, на стороне C API, это выглядит немного иначе. При вызове listen() через порт ОС начинает принимать подключения к этому порту. Это означает, что он начинает отвечать на пакеты SYN, ACK на соединения независимо от того, вызвал ли код C вызов accept(). Таким образом, на стороне TCP не имеет значения, является ли соединение каким-либо образом закрытым до или после принятия. Единственная дополнительная проблема заключается в том, что прослушивающий сокет имеет невыполненное задание, что означает число непринятых соединений, которые он может ожидать, прежде чем он начнет говорить RST удаленному концу.

Однако в Windows вызов SO_CONDITIONAL_ACCEPT позволяет приложению контролировать очередь невыполненных работ. Это означает, что сервер не будет отвечать что-либо на пакет SYN , пока приложение не выполнит что-либо с подключением. Это означает, что отклонение соединений на этом уровне может фактически отправлять RST пакетов в сеть без создания состояния.

Итак, если вы не можете каким-либо образом включить функцию SO_CONDITIONAL_ACCEPT в сокете, на котором вы используете AcceptEx, он будет отображаться по-другому для сети. Однако не так много мест фактически используют функциональность RST , так что я думаю, что требование для этого должно означать действительно очень специализированную систему. В большинстве случаев использование нормального способа поведения сокета, а затем его закрытие.

1 голос
/ 18 ноября 2009

Я не могу комментировать стороны Windows, но что касается TCP, отклонение соединение немного отличается от отключение от это.

Например, отключение от соединения означает, что было уже «использовано» больше ресурсов (например, состояние портов, сохраняемое в брандмауэрах и конечных точках, емкость пересылки, используемая в коммутаторах / маршрутизаторах и т. Д.) В обоих сеть и хосты. Отклонение соединения требует меньше ресурсов.

...