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