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