Я понимаю основы работы портов. Однако я не понимаю, как несколько клиентов могут одновременно подключаться, скажем, к порту 80. Я знаю, что у каждого клиента есть уникальный (для своей машины) порт. Отвечает ли сервер клиенту с доступного порта и просто заявляет, что ответ пришел с 80? Как это работает?
Как несколько клиентов одновременно подключаются к одному порту, скажем, 80 на сервере?
Ответы (5)
Во-первых, «порт» - это просто число. Все, что на самом деле представляет собой «соединение с портом», - это пакет, номер которого указан в поле заголовка «порт назначения».
Теперь есть два ответа на ваш вопрос: один для протоколов с отслеживанием состояния и один для протоколов без отслеживания состояния.
Для протокола без сохранения состояния (например, UDP) проблем нет, потому что «соединений» не существует - несколько человек могут отправлять пакеты на один и тот же порт, и их пакеты будут приходить в любой последовательности. Никто никогда не находится в «подключенном» состоянии.
Для протокола с отслеживанием состояния (например, TCP) соединение идентифицируется 4-кортежем, состоящим из портов источника и назначения, а также IP-адресов источника и назначения. Итак, если две разные машины подключаются к одному и тому же порту на третьей машине, есть два разных соединения, потому что исходные IP-адреса различаются. Если одна и та же машина (или две за NAT или иным образом использующие один и тот же IP-адрес) дважды подключается к одному удаленному концу, соединения различаются по исходному порту (который обычно является случайным портом с большим номером).
Проще говоря, если я дважды подключаюсь к одному и тому же веб-серверу с моего клиента, два подключения будут иметь разные исходные порты с моей точки зрения и порты назначения с веб-сервера. Таким образом, нет двусмысленности, даже если оба соединения имеют одинаковые IP-адреса источника и назначения.
Порты - это способ мультиплексирования IP-адресов, чтобы разные приложения могли прослушивать одну и ту же пару IP-адрес / протокол. Если приложение не определяет собственный протокол более высокого уровня, мультиплексировать порт невозможно. Если два соединения, использующие один и тот же протокол, одновременно имеют одинаковые IP-адреса источника и назначения и идентичные порты источника и назначения, они должны быть одним и тем же соединением.
netcat: bind failed: Address already in use
. Это сообщение в блоге привело меня к решению: ядро предотвращает повторное использование одного и того же исходного порта по соображениям надежности. Однако с опцией сокета SO_REUSEADDR
это возможно. С помощью этой опции я смог создать два соединения с одним и тем же исходным IP / портом, используя socat: socat - TCP:127.0.0.1:9000,sourceport=8000,reuseaddr
- person falstaff; 29.05.2017
Важно:
С сожалением вынужден сказать, что ответ от "Borealid" неточен и несколько неверен - во-первых, нет никакого отношения к сохранению состояния или без него, чтобы ответить на этот вопрос, и, что наиболее важно, определение кортежа для сокета неверно.
Сначала запомните два следующих правила:
Первичный ключ сокета: сокет идентифицируется
{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT, PROTOCOL}
, а не{SRC-IP, SRC-PORT, DEST-IP, DEST-PORT}
. Протокол является важной частью определения сокета.Сопоставление процессов ОС и сокетов: процесс может быть связан с несколькими сокетами (может открываться / прослушиваться), что может быть очевидно для многих читателей.
Пример 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", по сути, упомянул тот же правильный ответ, но ссылка на state -less / full была излишней / сбивала с толку.
Чтобы ответить на вторую часть вопроса о том, как сервер знает, на какой сокет отвечать. Сначала поймите, что для одного серверного процесса, который прослушивает один и тот же порт, может быть более одного сокета (может быть от одного клиента или от разных клиентов). Теперь, пока сервер знает, какой запрос связан с каким сокетом, он всегда может ответить соответствующему клиенту, используя тот же сокет. Таким образом, серверу никогда не нужно открывать другой порт в своем собственном узле, кроме исходного, к которому клиент изначально пытался подключиться. Если какой-либо сервер выделяет разные серверные порты после привязки сокета, то, на мой взгляд, сервер тратит свой ресурс, и ему, должно быть, нужно, чтобы клиент снова подключился к новому назначенному порту.
Еще немного для полноты:
Пример 2: Это очень интересный вопрос: «могут ли два разных процесса на сервере прослушивать один и тот же порт». Если вы не рассматриваете протокол как один из параметров, определяющих сокет, то ответ - нет. Это так, потому что мы можем сказать, что в таком случае один клиент, пытающийся подключиться к серверу-порту, не будет иметь никакого механизма, чтобы указать, к какому из двух прослушивающих процессов клиент намеревается подключиться. Это та же тема, что утверждается правилом (2). Однако это НЕПРАВИЛЬНЫЙ ответ, потому что «протокол» также является частью определения сокета. Таким образом, два процесса в одном узле могут прослушивать один и тот же порт, только если они используют разные протоколы. Например, два несвязанных клиента (скажем, один использует TCP, а другой - UDP) могут подключаться и взаимодействовать с одним и тем же серверным узлом и с одним и тем же портом, но они должны обслуживаться двумя разными серверными процессами.
Типы серверов - один и несколько:
Когда серверные процессы слушают порт, это означает, что несколько сокетов могут одновременно подключаться и взаимодействовать с одним и тем же серверным процессом. Если сервер использует только один дочерний процесс для обслуживания всех сокетов, тогда сервер называется однопроцессным / многопоточным, а если сервер использует много подпроцессов для обслуживания каждого сокета одним подпроцессом, тогда сервер называется многопоточным. процессный / поточный сервер. Обратите внимание, что независимо от типа сервера сервер может / должен всегда использовать один и тот же начальный сокет для ответа (нет необходимости выделять другой порт сервера).
Предлагаемые книги и остальные два тома, если можете .
Примечание о родительском / дочернем процессе (в ответ на запрос / комментарий Иоана Александру Куку)
Где бы я ни упоминал какую-либо концепцию в отношении двух процессов, например A и B, учитывайте, что они не связаны отношениями родитель-потомок. ОС (особенно UNIX) по своей конструкции позволяют дочернему процессу наследовать все файловые дескрипторы (FD) от родителей. Таким образом, все сокеты (в UNIX, подобных ОС, также являются частью FD), которые прослушивает процесс A, могут прослушиваться гораздо большим количеством процессов A1, A2, ..., если они связаны отношениями родитель-потомок с A. Но независимый процесс B (т.е. не имеющий отношения родитель-потомок к A) не может прослушивать тот же сокет. Кроме того, также обратите внимание, что это правило запрета двум независимым процессам прослушивать один и тот же сокет лежит в ОС (или ее сетевых библиотеках) и, безусловно, соблюдается большинством ОС. Однако можно создать собственную ОС, которая вполне может нарушить эти ограничения.
sendmsg()
system позвонить с SCM_RIGHTS
. Это верно не только для сокетов, но любой файловый дескриптор, принадлежащий процессу, может быть передан другому процессу, даже если он не является дочерним процессом.
- person Tuxdude; 27.04.2015
Прослушивание 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.) Соединения однозначно идентифицируются операционной системой с помощью следующих пяти кортежей: (локальный 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 -
Итак, теперь есть один процесс, который активно прослушивает (Состояние: 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-адресами никогда не бывает путаницы.
telnet localhost 500
- это более простой способ создать постоянное соединение.
- person Devs love ZenUML; 18.03.2017
nc 0.0.0.0 500
для подключения к серверу, а если вы используете python 2, `python -m SimpleHTTPServer 500` запускает http-сервер.
- person Jayhello; 25.10.2018
127.0.0.1:80 | 10.1.2.3:<random_port> | ESTABLISHED
невозможна.
- person user207421; 16.06.2019
Обычно для каждого подключающегося клиента сервер создает дочерний процесс, который взаимодействует с клиентом (TCP). Родительский сервер передает дочернему процессу установленный сокет, который отвечает клиенту.
Когда вы отправляете данные в сокет с вашего дочернего сервера, стек TCP в ОС создает пакет, возвращающийся клиенту, и устанавливает для параметра «порт отправителя» значение 80.
Несколько клиентов могут подключаться к одному и тому же порту (скажем, 80) на сервере, потому что на стороне сервера после создания сокета и привязки (установки локального IP-адреса и порта) listen вызывается в сокете, который сообщает ОС принимать входящие соединения.
Когда клиент пытается подключиться к серверу через порт 80, в сокете сервера вызывается вызов accept. Это создает новый сокет для клиента, пытающегося подключиться, и аналогично новые сокеты будут созданы для последующих клиентов, использующих тот же порт 80.
Слова, выделенные курсивом, - это системные вызовы.
Ссылка
http://www.scs.stanford.edu/07wi-cs244b/refs/net2.pdf