Отклонить TCP-соединение до его принятия?

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

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

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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