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

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

Заимствовать полуформальное определение:

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

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

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

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

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

Ответ 1

Ваша путаница заключается в том, что сокет идентифицируется сервером 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

Ответ 2

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

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

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

Apache на стороне сервера, говорящий на (server1.com:880-client1:1234 на TCP) а также Обсуждение World of Warcraft (server1.com:880-client1:1234 на UDP)

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

Ответ 3

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

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

Ответ 4

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

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

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