TCP: могут ли два разных сокета совместно использовать порт?
Это может быть очень простой вопрос, но меня это смущает.
Могут ли два разных подключенных сокета совместно использовать порт? Я пишу сервер приложений, который должен иметь возможность обрабатывать более 100 тыс. Параллельных подключений, и мы знаем, что количество доступных в системе портов составляет около 60 тыс. (16 бит). Подсоединенный сокет назначается новому (выделенному) порту, поэтому это означает, что количество параллельных подключений ограничено количеством портов, если только несколько сокетов не могут совместно использовать один и тот же порт. Так что вопрос.
Спасибо за помощь в продвижении!
- Отправка значения с сервера на клиент с сокетами
- Простой сервер сокетов в Unity
- «ab» программа зависает после множества запросов, почему?
- Нужно ли мне бить сердце, чтобы открыть TCP-соединение?
- Ошибка соединения Bluetooth "java.io.IOException: чтение не выполнено, сокет может быть закрыт или таймаут, read ret: -1"
Сету сервера прослушивает один порт. Все установленные клиентские соединения на этом сервере связаны с тем же самым портом прослушивания на стороне сервера соединения. Установленное соединение уникально идентифицируется комбинацией пар IP-портов на стороне клиента и на стороне сервера. Несколько соединений на одном и том же сервере могут совместно использовать одну и ту же пару IP-портов на стороне сервера, если они связаны с разными клиентскими IP-портами, и сервер сможет обрабатывать столько клиентов, сколько доступно доступным системным ресурсам к.
На клиентской стороне обычно для новых исходящих подключений используется случайный порт на стороне клиента , и в этом случае можно выходить из доступных портов, если вы заработаете много соединений за короткий промежуток времени.
Прослушивание TCP / HTTP в портах: как многие пользователи могут использовать один и тот же порт
Итак, что происходит, когда сервер прослушивает входящие соединения на TCP-порт? Например, предположим, что у вас есть веб-сервер на порту 80. Предположим, что ваш компьютер имеет общеansible IP-адрес 24.14.181.229, а человек, пытающийся подключиться к вам, имеет IP-адрес 10.1.2.3. Этот человек может подключиться к вам, открыв сокет TCP до 24.14.181.229:80. Достаточно просто.
Интуитивно (и ошибочно), большинство людей считают, что это выглядит примерно так:
Local Computer | Remote Computer -------------------------------- :80 | :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.) На сервере процесс прослушивает порт. Как только он получает соединение, он передает его в другой stream. Связь никогда не заставляет прослушивающий порт.
2.) Соединения уникально идентифицируются ОС следующим 5-кортежем: (локальный-IP-адрес, локальный порт, удаленный IP-протокол, удаленный порт, протокол). Если какой-либо элемент в кортеже отличается, то это полностью независимое соединение.
3.) Когда клиент подключается к серверу, он выбирает случайный неиспользуемый порт источника высокого порядка . Таким образом, один клиент может иметь до ~ 64 к подключений к серверу для одного и того же порта назначения.
Таким образом, это действительно то, что создается, когда клиент подключается к серверу:
Local Computer | Remote Computer | Role ----------------------------------------------------------- 0.0.0.0:80 | | LISTENING 127.0.0.1:80 | 10.1.2.3: | 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.
Это простой скрипт ( 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-адресами никогда не возникает путаницы.
Подключенный сокет назначается новому (выделенному) порту
Это обычная интуиция, но это неверно. Подсоединенный разъем не назначается новому / выделенному порту. Единственным фактическим ограничением, которое должен удовлетворять стек 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
Теоретически, да. Практика нет. Большинство ядер (включая linux) не позволяют вам bind()
второй bind()
к уже выделенному порту. Это не было действительно большим патчем, чтобы это разрешилось.
В общем случае мы должны различать разъем и порт . Сокеты – это двунаправленные конечные точки связи, то есть «вещи», где мы можем отправлять и принимать байты. Это концептуальная вещь, нет такого поля в заголовке пакета с именем «socket».
Порт – это идентификатор, который способен идентифицировать сокет. В случае TCP порт представляет собой 16-битное целое число, но есть и другие протоколы (например, в Unix-сокетах, «порт» по существу является строкой).
Основная проблема заключается в следующем: если поступает входящий пакет, kernel может идентифицировать его сокет по его номеру порта назначения. Это самый распространенный способ, но это не единственная возможность:
- Сокеты могут быть идентифицированы IP-адресом назначения входящих пакетов. Это имеет место, например, если у нас есть сервер, использующий два IP одновременно. Затем мы можем запускать, например, различные веб-серверы на одних и тех же портах, но на разных IP-адресах.
- Сокеты могут быть идентифицированы по их исходному порту и ip. Это имеет место во многих конфигурациях балансировки нагрузки.
Поскольку вы работаете на сервере приложений, он сможет это сделать.