API сокетов де-факто является стандартом для связи TCP / IP и UDP / IP (то есть сетевого кода в том виде, в каком мы его знаем). Однако одна из его основных функций accept()
немного волшебна.
Чтобы заимствовать полуформальное определение:
accept () используется на стороне сервера. Он принимает полученную входящую попытку создать новое TCP-соединение от удаленного клиента и создает новый сокет, связанный с парой адресов сокета этого соединения.
Другими словами, accept
возвращает новый сокет, через который сервер может общаться с вновь подключенным клиентом. Старый сокет (на котором accept
был вызван) остается открытым на том же порту, ожидая новых подключений.
Как accept
работает? Как это реализовано? По этой теме много путаницы. Многие утверждают, что accept открывает новый порт, через который вы общаетесь с клиентом. Но это, очевидно, неправда, поскольку новый порт не открывается. На самом деле вы можете общаться через один порт с разными клиентами, но как? Когда несколько потоков обращаются recv
к одному и тому же порту, как данные узнают, куда идти?
Я предполагаю, что это что-то вроде адреса клиента, связанного с дескриптором сокета, и всякий раз, когда данные проходят через recv
него, они направляются в правильный сокет, но я не уверен.
Было бы здорово получить подробное объяснение того, как работает этот механизм.
источник
Ответы:
Ваше замешательство заключается в том, что вы думаете, что сокет идентифицируется как 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.2
открывает соединение на локальном порту5678
и подключается к серверу. Теперь у сервера есть два сокета, обозначенных следующим образом:источник
Просто чтобы добавить к ответу пользователя "17 из 26"
На самом деле сокет состоит из 5 кортежей - (исходный IP-адрес, исходный порт, целевой IP-адрес, целевой порт, протокол). Здесь протоколом может быть TCP или UDP или любой протокол транспортного уровня. Этот протокол идентифицируется в пакете из поля «протокол» дейтаграммы IP.
Таким образом, возможно, что разные приложения на сервере будут взаимодействовать с одним и тем же клиентом с помощью одних и тех же четырех кортежей, но с разными полями протокола. Например
Apache на стороне сервера разговаривает (server1.com:880-client1:1234 по TCP) и World of Warcraft разговаривает (server1.com:880-client1:1234 по UDP)
И клиент, и сервер будут обрабатывать это, поскольку поле протокола в IP-пакете в обоих случаях отличается, даже если все остальные 4 поля одинаковы.
источник
Когда я изучал это, меня смущало то, что термины
socket
иport
предполагают, что они являются чем-то физическим, хотя на самом деле это просто структуры данных, которые ядро использует для абстрагирования деталей сети.Таким образом, структуры данных реализованы так, чтобы иметь возможность отделить соединения от разных клиентов. Что касается того, как они реализованы, ответ будет либо а.) Не имеет значения, цель API сокетов именно в том, чтобы реализация не имела значения, или б.) Просто посмотрите. Помимо настоятельно рекомендуемых книг Стивенса, содержащих подробное описание одной реализации, ознакомьтесь с исходным кодом в Linux, Solaris или одной из BSD.
источник
Как сказал другой парень, сокет однозначно идентифицируется четырьмя кортежами (клиентский IP, клиентский порт, серверный IP, серверный порт).
Серверный процесс, запущенный на IP-адресе сервера, поддерживает базу данных (то есть меня не волнует, какую таблицу / список / дерево / массив / магическую структуру данных он использует) активных сокетов и прослушивает порт сервера. Когда он получает сообщение (через стек TCP / IP сервера), он проверяет клиентский IP и порт по базе данных. Если IP-адрес клиента и порт клиента находятся в записи базы данных, сообщение передается существующему обработчику, в противном случае создается новая запись в базе данных и создается новый обработчик для обработки этого сокета.
На заре ARPAnet определенные протоколы (например, FTP) слушали указанный порт для запросов на соединение и отвечали портом передачи обслуживания. Дальнейшая связь для этого соединения будет проходить через порт передачи обслуживания. Это было сделано для повышения производительности отдельных пакетов: в те дни компьютеры были на несколько порядков медленнее.
источник