Код стека TCP / IP в ядре обычно [1] завершает трехстороннее рукопожатие полностью без вмешательства какого-либо пользовательского кода. Все три шага, которые вы перечисляете, происходят за до accept()
возврата. Действительно, они могут произойти до того, как accept()
даже будет вызван!
Когда вы указываете стеку listen()
для соединений через определенный порт TCP, вы передаете параметр backlog
, который сообщает ядру, сколько соединений он может молча принимать от имени вашей программы одновременно. Именно эта очередь используется, когда ядро автоматически принимает новые запросы на соединение, и там они удерживаются до тех пор, пока ваша программа не получит их accept()
. Когда при вызове accept()
имеется одно или несколько подключений в очереди прослушивания, все, что происходит, это то, что самое старое удаляется из очереди и связывается с новым сокетом. [2]
Другими словами, если ваша программа вызывает listen(sd, 5)
, то входит в бесконечный цикл бездействия, так что она никогда не вызывает accept()
, с точки зрения клиентов пять одновременных запросов клиентского соединения будут выполнены успешно. Шестой запрос на подключение будет остановлен на первом пакете SYN, пока программа, владеющая портом TCP, не вызовет accept()
, или один из других клиентов не разорвет свое соединение.
[1] Брандмауэр и другие модификации стека, конечно, могут изменить это поведение. Я говорю только о поведении стека сокетов BSD по умолчанию.
[2] Если нет никаких соединений, ожидающих в очереди, когда вы вызываете accept()
, он блокируется по умолчанию, если сокет слушателя не был установлен неблокирующим, в этом случае он возвращает -1 и errno
EWOULDBLOCK
.