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

этот вопрос уже есть ответ здесь:

  • изменяется ли порт, когда сервер принимает TCP-соединение? 2 ответы

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

5 ответов


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

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

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

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

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

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


важно:

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

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

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

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

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

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

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

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

немного больше для полноты:

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

типы серверов-single & multiple:

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

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

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

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


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:порт. Так как клиент подключается к порту 80, то его порт тоже должен быть 80? Это разумная вещь, чтобы думать, но на самом деле не происходит. Если бы это было правильно, мы могли бы обслуживать только одного пользователя на иностранный IP-адрес. Как только удаленный компьютер подключится, он будет использовать порт 80 подключение к порту 80, и никто не мог подключиться.

необходимо понять три вещи:

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

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

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

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

    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      - 

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

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

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

это простой скрипт (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-адресами.


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

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


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

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

слова курсивом-это системные вызовы.

Ref

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