Как работает функция API сокета accept ()?

API сокета является стандартом де-факто для TCP/IP и UDP / IP-коммуникаций (то есть сетевого кода, как мы его знаем). Однако, одна из его основных функций,accept() немного волшебным.

чтобы заимствовать полуформальное определение:

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

другими словами, accept возвращает новый сокет, через который сервер может взаимодействовать с вновь подключенным клиентом. Старый сокет (на котором accept был вызван) остается открытым, на том же порту, прослушивая новые соединения.

как accept работы? Как она реализуется? В этой теме много путаницы. Многие люди утверждают, что принимают открывает новый порт и вы общаетесь с клиентом через него. Но это, очевидно, не так, как нет открывается новый порт. Вы действительно можете общаться через один и тот же порт с разными клиентами, но как? Когда несколько потоков вызывают recv на том же порту, как данные знают, куда идти?

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

было бы здорово получить подробное объяснение внутренней работы этот механизм.

4 ответов


ваша путаница заключается в том, что вы думаете, что сокет идентифицируется сервером IP : порт сервера. Когда на самом деле сокеты однозначно идентифицируются квартетом информации:

Client IP : Client Port и Server IP : Server Port

таким образом, в то время как IP-адрес сервера и порт сервера постоянны во всех принятых соединениях, информация на стороне клиента позволяет отслеживать, где все происходит.

пример для уточнения вещей:

скажем, у нас есть сервер на 192.168.1.1: 80 и два клиента, 10.0.0.1 и 10.0.0.2.

10.0.0.1 открывает соединение на локальном порту 1234 и подключается к серверу. Теперь у сервера есть один сокет, идентифицированный следующим образом:

10.0.0.1:1234 - 192.168.1.1:80

теперь 10.0.0.2 открывает соединение на локальном порту 5678 и подключается к серверу. Теперь сервер имеет два сокета, идентифицированных следующим образом:

10.0.0.1:1234 - 192.168.1.1:80
10.0.0.2:5678 - 192.168.1.1:80


просто добавить к ответу, данному пользователем "17 из 26"

сокет фактически состоит из 5 кортежей - (исходный ip, исходный порт, IP назначения, порт назначения, протокол). Здесь протокол может TCP или UDP или любой протокол транспортного уровня. Этот протокол идентифицируется в пакете из поля "протокол" в IP-дейтаграмме.

таким образом, можно иметь разные приложения на сервере, связывающиеся с одним и тем же клиентом на точно таких же 4-кортежах но разные в протокольном поле. Например

Apache на стороне сервера разговаривает (server1.com: 880-client1:1234 на TCP) и World of Warcraft talking on (server1.com: 880-client1: 1234 на UDP)

и клиент, и сервер будут обрабатывать это как поле протокола в IP-пакете в обоих случаях отличается, даже если все остальные 4 поля одинаковы.


что смутило меня, когда я изучал это, было то, что термины socket и port предположим, что они являются чем-то физическим, когда на самом деле это просто структуры данных, которые ядро использует для абстракции деталей сети.

таким образом, структуры данных реализованы, чтобы иметь возможность отделять соединения от разных клиентов. Как как они реализованы, ответ либо a.) это не имеет значения, цель API сокетов именно в том, что реализация не должна иметь значения или b.) просто взгляните. Помимо настоятельно рекомендованных книг Стивенса, содержащих подробное описание одной реализации, проверьте источник в Linux или Solaris или одном из BSD.


Как сказал другой парень, сокет однозначно идентифицируется 4-кортежем (IP клиента, порт клиента, IP сервера, порт сервера).

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

в первые дни ARPAnet некоторые протоколы (FTP для одного) прослушивали указанный порт для запросов на подключение и отвечали портом передачи. Дальнейшая связь для этого соединения будет осуществляться через порт передачи. Это было сделано для повышения производительности каждого пакета: компьютеры были несколько порядков магнитуда в те дни была медленнее.