Подтвердить что ты не робот

TCP: могут ли два разных сокета совместно использовать порт?

Это может быть очень простой вопрос, но меня это смущает.

Может ли два разных подключенных сокета совместно использовать порт? Я пишу сервер приложений, который должен иметь возможность обрабатывать более 100 тыс. Параллельных подключений, и мы знаем, что количество доступных в системе портов составляет около 60 тыс. (16 бит). Подсоединенный сокет назначается новому (выделенному) порту, поэтому это означает, что количество параллельных подключений ограничено количеством портов, если только несколько сокетов не могут совместно использовать один и тот же порт. Так что вопрос.

Спасибо за помощь заранее!

4b9b3361

Ответ 1

Сокет сервер прослушивает один порт. Все установленные клиентские соединения на этом сервере связаны с тем же самым портом прослушивания на стороне сервера. Установленное соединение уникально идентифицируется комбинацией пар IP-портов на стороне клиента и на стороне сервера. Несколько соединений на одном и том же сервере могут совместно использовать одну и ту же пару на стороне сервера, если они связаны с разными парами IP/портов на стороне клиента, а сервер сможет обрабатывать столько клиентов, сколько позволяют доступные системные ресурсы.

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

Ответ 2

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

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

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

Это простой script (https://github.com/grokit/quickweb), который открывает сокет 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-адресами никогда не возникает путаницы.

Ответ 3

Подключенный сокет назначается новому (выделенному) порту

Это общая интуиция, но она неверна. Подсоединенный разъем не назначается новому/выделенному порту. Единственным фактическим ограничением, которое должен удовлетворять стек TCP, является то, что кортеж (local_address, local_port, remote_address, remote_port) должен быть уникальным для каждого соединения сокета. Таким образом, сервер может иметь много сокетов TCP, используя один и тот же локальный порт, если каждый из сокетов на порту подключен к другому удаленному местоположению.

См. параграф "Socket Pair": http://books.google.com/books?id=ptSC4LpwGA0C&lpg=PA52&dq=socket%20pair%20tuple&pg=PA52#v=onepage&q=socket%20pair%20tuple&f=false

Ответ 4

Теоретически, да. Практика нет. Большинство ядер (включая linux) не позволяют вам второй bind() для уже выделенного порта. Это не было действительно большим патчем, чтобы это разрешалось.

Заключительно, мы должны различать разъем и порт. Сокеты представляют собой двунаправленные конечные точки связи, то есть "вещи", где мы можем отправлять и принимать байты. Это концептуальная вещь, нет такого поля в заголовке пакета с именем "socket".

Порт - это идентификатор, который способен идентифицировать сокет. В случае TCP порт представляет собой 16-битное целое число, но есть и другие протоколы (например, в Unix-сокетах, "порт" по существу является строкой).

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

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

Поскольку вы работаете на сервере приложений, он сможет это сделать.