Как несколько клиентов одновременно подключаются к одному порту, например 80, на сервере?

Я понимаю основы работы портов. Однако я не понимаю, как несколько клиентов могут одновременно подключаться к порту 80. Я знаю, что каждый клиент имеет уникальный (для своего компьютера) порт. Отвечает ли сервер обратно с доступного порта клиенту и просто заявляет, что ответ пришел с 80? Как это работает?

Ответ 1

Во-первых, "порт" - это просто число. Все, что действительно представляет собой "соединение с портом", - это пакет, номер которого указан в поле заголовка "порт назначения".

Теперь есть два ответа на ваш вопрос, один для протоколов с сохранением состояния и один для протоколов без сохранения состояния.

Для протокола без сохранения состояния (т.е. UDP) проблем нет, поскольку "соединений" не существует - несколько человек могут отправлять пакеты на один и тот же порт, и их пакеты будут поступать в любой последовательности. Никто никогда не находится в "связанном" состоянии.

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

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

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

Ответ 2

Важно:

Мне жаль говорить, что ответ от "Borealid" неточен и несколько некорректен - во-первых, нет никакого отношения к состоянию или безгражданству, чтобы ответить на этот вопрос, и, самое главное, определение кортежа для сокета неверно.

Сначала запомните два правила:

  1. Первичный ключ сокета: сокет идентифицируется {SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL}, а не {SRC-IP, SRC-PORT, DEST-IP, DEST-PORT} - протокол является важной частью определения сокета.

  2. ОС Процесс & Сопоставление сокетов: процесс может быть связан (может открывать/прослушивать) с несколькими сокетами, что может быть очевидно для многих читателей.

Пример 1: Два клиента, подключающиеся к одному и тому же порту сервера, означают: socket1 {SRC-A, 100, DEST-X,80, TCP} и socket2{SRC-B, 100, DEST-X,80, TCP}. Это означает, что хост A подключается к серверу X порт 80, а другой хост B также подключается к тому же серверу X к тому же порту 80. Теперь то, как сервер обрабатывает эти два сокета, зависит от того, является ли сервер однопоточным или многопоточным (я буду объясню позже) Важно то, что один сервер может одновременно прослушивать несколько сокетов.

Чтобы ответить на оригинальный вопрос поста:

Независимо от протоколов с состоянием или без состояния, два клиента могут подключаться к одному и тому же порту сервера, потому что для каждого клиента мы можем назначить разные сокеты (поскольку IP-адрес клиента определенно будет отличаться). Один и тот же клиент может также иметь два сокета, соединяющихся с одним и тем же портом сервера, поскольку такие сокеты отличаются на SRC-PORT. Справедливости ради, "Бореалид", по сути, упомянул тот же правильный ответ, но ссылка на "без состояния/полный" была немного ненужной/запутанной.

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

Еще немного для полноты:

Пример 2: Это очень интересный вопрос, может ли сервер два разных процесса прослушивать один и тот же порт. Если вы не рассматриваете протокол как один из параметров, определяющих сокет, то ответ - нет. Инициативно это так, потому что мы можем сказать, что в таком случае для одного клиента, пытающегося подключиться к порту сервера, не будет никакого механизма, чтобы указать, какой из двух процессов прослушивания клиент намеревается. Это та же тема, что утверждена в правиле (2). Однако это НЕПРАВИЛЬНЫЙ ответ, потому что "протокол" также является частью определения сокета. Таким образом, два процесса в одном узле могут прослушивать один и тот же порт, только если они используют разные протоколы. Например, два несвязанных клиента (скажем, один использует TCP, а другой использует UDP) могут связывать подключение и связь с одним и тем же узлом сервера и с одним и тем же портом, но они должны обслуживаться двумя разными серверными процессами.

Типы серверов - один & многообразны:

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

Предлагаемые книги и остальные два тома, если можете.

Примечание о родительском/дочернем процессе (в ответ на запрос/комментарий "Ioan Alexandru Cucu")

Где бы я ни упомянул какую-либо концепцию в отношении двух процессов, скажем, A и B, учтите, что они не связаны родительскими дочерними отношениями. ОС (особенно UNIX) по своему дизайну позволяют дочернему процессу наследовать все дескрипторы файлов (FD) от родителей. Таким образом, все сокеты (в UNIX-подобных ОС также являются частью FD), которые прослушивает процесс A, могут прослушиваться многими другими процессами A1, A2,.., если они связаны отношением "родитель-потомок" к A. независимый процесс B (т.е. не имеющий отношения родитель-потомок к A) не может прослушивать один и тот же сокет. Кроме того, также обратите внимание, что это правило, запрещающее двум независимым процессам прослушивать один и тот же сокет, находится в ОС (или в ее сетевых библиотеках) и, безусловно, подчиняется большинству ОС. Однако можно создать собственную ОС, которая вполне может нарушить эти ограничения.

Ответ 3

Прослушивание TCP/HTTP в портах: как многие пользователи могут использовать один и тот же порт

Итак, что происходит, когда сервер прослушивает входящие соединения на TCP-порт? Например, скажем, у вас есть веб-сервер на порту 80. Предположим, что ваш компьютер имеет общедоступный IP-адрес 24.14.181.229, а человек, пытающийся подключиться к вам, имеет IP-адрес 10.1.2.3. Этот человек может подключиться к вам, открыв сокет TCP до 24.14.181.229:80. Достаточно просто.

Интуитивно (и ошибочно), большинство людей считают, что это выглядит примерно так:

    Local Computer    | Remote Computer
    --------------------------------
    <local_ip>:80     | <foreign_ip>:80

    ^^ not actually what happens, but this is the conceptual model a lot of people have in mind.

Это интуитивно понятно, потому что с точки зрения клиента он имеет IP-адрес и подключается к серверу через IP: PORT. Поскольку клиент подключается к порту 80, то его порт должен быть тоже 80? Это разумная вещь, чтобы думать, но на самом деле не то, что происходит. Если бы это было правильно, мы могли обслуживать только одного пользователя на чужой IP-адрес. Как только удаленный компьютер подключится, он будет подключать порт 80 к порту 80, и никто не сможет подключиться.

Следует понимать три вещи:

1.) На сервере процесс прослушивает порт. Как только он получает соединение, он передает его в другой поток. Связь никогда не заставляет прослушивающий порт.

2.) Соединения однозначно идентифицируются ОС следующим 5-кортежем: (локальный-IP-адрес, локальный порт, удаленный IP-протокол, удаленный порт, протокол). Если какой-либо элемент в кортеже отличается, то это полностью независимое соединение.

3.) Когда клиент подключается к серверу, он выбирает случайный неиспользуемый порт источника высокого порядка. Таким образом, один клиент может иметь до ~ 64 тыс. Подключений к серверу для одного и того же порта назначения.

Итак, это действительно то, что создается, когда клиент подключается к серверу:

    Local Computer   | Remote Computer           | Role
    -----------------------------------------------------------
    0.0.0.0:80       | <none>                    | LISTENING
    127.0.0.1:80     | 10.1.2.3:<random_port>    | ESTABLISHED

Глядя на то, что происходит на самом деле

Во-первых, позвольте использовать netstat, чтобы увидеть, что происходит на этом компьютере. Мы будем использовать порт 500 вместо 80 (потому что на порту 80 происходит целая куча вещей, поскольку это общий порт, но функционально это не имеет значения).

    netstat -atnp | grep -i ":500 "

Как и ожидалось, вывод пуст. Теперь запустите веб-сервер:

    sudo python3 -m http.server 500

Теперь вот результат запуска netstat:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      - 

Итак, теперь есть один процесс, который активно прослушивает (State: LISTEN) на порту 500. Локальный адрес 0.0.0.0, который является кодом для "прослушивания всех". Простая ошибка заключается в прослушивании адреса 127.0.0.1, который будет принимать только соединения с текущего компьютера. Таким образом, это не соединение, это просто означает, что процесс запросил привязать() к IP-порту, и этот процесс отвечает за обработку всех подключений к этому порту. Это указывает на ограничение того, что на компьютере может быть только один процесс, который прослушивает порт (есть способы обойти это с использованием мультиплексирования, но это гораздо более сложная тема). Если веб-сервер прослушивает порт 80, он не может обмениваться этим портом с другими веб-серверами.

Итак, теперь подключите пользователя к нашей машине:

    quicknet -m tcp -t localhost:500 -p Test payload.

Это простой script (https://github.com/grokit/dcore/tree/master/apps/quicknet), который открывает сокет TCP, отправляет полезную нагрузку ( "тестовая нагрузка" в этот случай), ждет несколько секунд и отключается. Повторное выполнение netstat при этом происходит следующим образом:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:54240      ESTABLISHED -

Если вы подключитесь к другому клиенту и снова выполните netstat, вы увидите следующее:

    Proto Recv-Q Send-Q Local Address           Foreign Address         State  
    tcp        0      0 0.0.0.0:500             0.0.0.0:*               LISTEN      -
    tcp        0      0 192.168.1.10:500        192.168.1.13:26813      ESTABLISHED -

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

Ответ 4

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

Когда вы отправляете данные в сокет с вашего дочернего сервера, стек TCP в ОС создает пакет, возвращающийся к клиенту, и устанавливает "от порта" до 80.

Ответ 5

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

Когда клиент пытается подключиться к серверу на порту 80, вызов accept вызывается в сокет сервера. Это создает новый сокет для клиента, пытающегося подключиться, и аналогичные новые сокеты будут созданы для последующих клиентов, используя тот же порт 80.

Словами курсивом являются системные вызовы.

Ссылка

http://www.scs.stanford.edu/07wi-cs244b/refs/net2.pdf