Чи можуть два додатки прослуховувати один і той же порт?


283

Чи можуть дві програми на одній машині прив’язатись до одного порту та IP-адреси? Зробивши це крок далі, чи може одна програма прослуховувати запити, що надходять із певного IP, а інша - до іншого віддаленого IP? Я знаю, що у мене може бути одна програма, яка починає два потоки (або вилки), щоб мати подібну поведінку, але чи можуть два програми, які не мають нічого спільного, зробити те саме?


2
Щоб отримати детальну відповідь про повторне використання адрес / портів з кількома сокетами: stackoverflow.com/questions/14388706/…
Bjarke Freund-Hansen

Відповіді:


248

Відповідь відрізняється залежно від того, яку ОС розглядають. Загалом, хоча:

Для TCP немає. Ви можете одночасно прослуховувати одну програму на одному порту. Тепер, якщо у вас були 2 мережеві карти, ви могли б прослухати одну програму під час першого IP-адреси, а другу - на другий IP-адресу, використовуючи той самий номер порту.

Для UDP (Multicasts) на один і той же порт можуть підписатися кілька додатків.

Редагувати: Оскільки Linux Kernel 3.9 та пізніших версій, додано підтримку декількох програм, які прослуховують один і той же порт, використовуючи цю SO_REUSEPORTопцію. Більше інформації можна знайти в цій статті lwn.net.


22
"прослуховування однієї програми на одному порту" - це причина існування портів - щоб дозволити безлічі додатків ділитися мережею без конфліктів.
S.Lott

46
Один слухач на порт на IP-адресу. Додавання іншого мережевого інтерфейсу - це спосіб отримати другу IP-адресу. Ваша платформа, ймовірно, підтримує віртуальні інтерфейси, що є ще одним способом отримання двох IP-адрес за допомогою однієї фізичної мережевої карти.
Джон М

7
Хоча до цього часу я був такої ж думки, виявляється, мені вдалося прив’язати два різні процеси до одного ip та TCP-порту! Це можливо, якщо ви встановите ServerSocket.setReuseAddress (true) в Java перед прив'язкою до неї. Дійсно несподівана поведінка.
Євген

7
(1) Справжнє значення вашої відповіді - "Для TCP, так, за умови ..." (2) Багатоадресна передача не є обов'язковою умовою для спільного використання портів UDP, але SO_REUSEADDR є.
Маркіз Лорн

12
Для UDP (Multicasts) на один і той же порт можуть підписатися кілька додатків. Якщо один пакет надійшов від клієнта, яка програма отримує його?
Ян Ювен

123

Так (для TCP) ви можете прослуховувати дві програми в одному сокеті, якщо програми призначені для цього. Коли сокет створений першою програмою, переконайтеся, що SO_REUSEADDRпараметр встановлений на розетці перед вами bind(). Однак це може бути не те, що ви хочете. Це означає, що вхідне TCP-з'єднання буде спрямоване на одну з програм, а не на обидві, тому воно не дублює з'єднання, воно просто дозволяє двом програмам обслуговувати вхідний запит. Наприклад, веб-сервери матимуть безліч процесів, які прослуховують порт 80, і O / S надсилає нове з'єднання до процесу, який готовий прийняти нові з'єднання.

SO_REUSEADDR

Дозволяє іншим сокетам до bind()цього порту, за винятком випадків, коли до порту вже є активна розетка прослуховування. Це дає змогу обійти ці повідомлення про помилки "Адреса вже використовується" під час спроби перезапустити сервер після збоїв.


1
TCP + UDP тепер працює (дається нове достатнє ядро). Дивіться посилання, яке я додав до відповіді.
dpb

3
Ця відповідь є невірною, якщо всі сокети не пов'язані з різними IP-адресами, жодна з яких не є INADDR_ANY, або якщо ви не знаходитесь у Windows, де результат не визначений.
Маркіз Лорн

1
Чи можете ви розширити, як дані надходять до певної програми на тому ж порту? Чи є якісь проблеми щодо безпеки, коли варто задуматися, коли програми використовують SO_REUSEADDR або SO_REUSEPORT?
trusktr

@EJP Чи можете ви також поглянути на мій попередній коментар?
trusktr

3
SO_REUSEADDRзвичайно не дозволяє вам мати два TCP-розетки в стані прослуховування одночасно, принаймні на Unix. Це призначено обійти TIME_WAIT state: unixguide.net/network/socketfaq/4.5.shtml . Це може працювати в Windows, але ви не впевнені, що запит все одно надійде до потрібного сервера).
Бруно

48

Так.

  1. Багаторазові прослуховування TCP-розеток, всі прив’язані до одного порту, можуть співіснувати за умови, що всі вони пов'язані з різними локальними IP-адресами. Клієнти можуть підключитися до того, що їм потрібно. Це виключає 0.0.0.0( INADDR_ANY).

  2. Можуть існувати декілька прийнятих розеток, усі приймаються з одного і того ж розетки для прослуховування, всі показують той же номер локального порту, що і розетка для прослуховування.

  3. Безліч UDP-сокетів, які прив'язані до одного порту, можуть співіснувати за умови тієї ж умови, що і в (1), або всі вони мали SO_REUSEADDRможливість встановити перед прив'язкою.

  4. TCP-порти та порти UDP займають різні простори імен, тому використання порту для TCP не виключає його використання для UDP, і навпаки.

Довідка: Stevens & Wright, TCP / IP Illustrated, том II.


у вас є посилання під рукою? Можливість співжиття TCP-UDP - це саме моє запитання. Заздалегідь дякую :)
Вовк

1
@Wolf Просто спробуйте. Це все доказ, який вам справді потрібен. Моя цитата - Стівенс і Райт: ви не можете набагато краще, ніж це.
Маркіз Лорн

1
Дякую за відповідь, мені потрібно прочитати ще уважніше. Ви вже писали, що UDP і TCP можуть співіснувати .
Вовк

47

В принципі, ні.

Це не написано каменем; але так написано всі API: додаток відкриває порт, отримує обробку з ним, і ОС повідомляє про це (через цю ручку), коли клієнтське з'єднання (або пакет у випадку UDP) надходить.

Якщо ОС дозволила двом додаткам відкривати один і той же порт, то як би він знати, який з них повідомити?

Але ... існують способи:

  1. Як зазначив Джед , ви можете написати "головний" процес, який був би єдиним, хто насправді слухає на порту та повідомляє інших, використовуючи будь-яку логіку, яку він хоче розділити.
    • У Linux та BSD (принаймні) ви можете встановити правила "перезавантаження", які перенаправляють пакети з "видимого" порту на різні (де програми прослуховуються), відповідно до будь-яких мережевих критеріїв (можливо, мережа походження чи деякі прості форми балансування навантаження).

37
iptables -m statistic --mode random --probability 0.5весело.
Джед Сміт

1
Що саме означає "Відкриває порт"? Я розумію речення, але чи знаєте ви, що саме система робить, коли відкриває порт і обробляє його? Я знаю, що коли ви хочете відкрити порт за допомогою TCP, ви отримуєте потік, і цей потік є вашим зв’язком з віддаленим, але я шукаю в Інтернеті і не знайшов дуже хорошого пояснення.
Самуїл

4
@Samuel: відкриття порту (в режимі сервера) означає отримання дескриптора файлу, і коли система отримує SYN-пакет на цей номер порту, відповідає SYN + ACK і генерує подію на пов'язаному дескрипторі файлу. додаток відповідає на цю подію на виклик accept (), який створює новий дескриптор файлу, пов’язаний із певним потоком, залишаючи оригінальний дескриптор сервера вільним для отримання нових з'єднань з клієнтами
Хав'єр

7
Цю відповідь не можна вважати правильною. Це повністю оглядає існування як SO_REUSEADDR, так і SO_REUSEPORT.
Маркіз Лорн

@Javier Ні, це не так. Відкриття порту з точки зору серверного додатка відбувається, коли ви прив'язуєте розетку прослуховування, а точніше зв'язуєте сокет, про який ви збираєтесь listen(). Більш ймовірно, питання полягає у відкритті його в брандмауері. Тут надто багато помилок, і всі не виправлені за 7 років. Відповідь також ухиляє випадок прив’язки до різної локальної адреси з тим самим номером порту. Це насправді абсолютно некоректно.
Маркіз Лорн

27

Так, безумовно . Наскільки я пам’ятаю З ядра версії 3.9 (Не впевнений у версії) далі SO_REUSEPORTбула представлена підтримка для . SO_RESUEPORTдозволяє прив’язувати до того самого порту та адреси, поки перший сервер встановлює цю опцію перед прив’язкою свого сокета.

Він працює як для TCP, так і для UDP . Щоб отримати докладнішу інформацію, перейдіть за посиланням: SO_REUSEPORT

Примітка : прийнята відповідь більше не відповідає дійсності, на мій погляд.


2
Цілком вірно. Якщо це не було правдою, як Wireshark міг працювати?
Сташек

5
@Staszek Wireshark не слухає порти. Він працює на рівні пакетів.
Маркіз Лорн

О, це мало б сенс. У будь-якому разі, прослуховування двох портів за допомогою двох додатків, безумовно, можливо.
Сташек

18

Ні. Лише одна програма може одночасно прив'язуватися до порту, а поведінка, якщо прив'язка примусово, невизначена.

З багатоадресною розеткою - яка звучить як ніде поблизу того, що ви хочете - більш ніж одна програма може прив’язуватися до порту, доки в опціях кожного сокета встановлено SO_REUSEADDR.

Ви можете досягти цього, написавши «головний» процес, який приймає та обробляє всі з'єднання, а потім передає їх вашим двом програмам, яким потрібно слухати на одному порті. Це такий підхід, який застосовують веб-сервери і подібні, оскільки в багатьох процесах потрібно прослуховувати 80.

Крім цього, ми розбираємось у специфіці - ви позначили як TCP, так і UDP, що це? Також, яка платформа?


обидва мене цікавлять. Платформа - це windows, але якщо відповідь для Linux відрізняється, було б непогано знати
nadiv

8
Немає такого поняття, як багатоадресна розетка. Є розетки UDP. Багатоадресна передача не є необхідною умовою для SO_REUSEADDR.
Маркіз Лорн

3

Ви можете прослуховувати одну програму на одному порту для одного мережевого інтерфейсу. Тому ви могли:

  1. httpd прослуховування через віддалено доступний інтерфейс, наприклад 192.168.1.1:80
  2. ще один демон, що слухає 127.0.0.1:80

Випадок використання зразка може бути використаний httpdяк балансир навантаження або проксі.


3

Іншим способом є використання програми прослуховування в одному порту, який аналізує тип трафіку (ssh, https тощо), який він внутрішньо перенаправляє на інший порт, на якому слухає "справжній" сервіс.

Наприклад, для Linux sslh: https://github.com/yrutschle/sslh


Чи є така програма на windows? Мені потрібно, щоб мій локальний сервер IIS та брокер ActiveMQ слухали на порту 443
Harvey Lin,

3

Коли ви створюєте TCP-з'єднання, ви просите підключитися до певної адреси TCP, яка є комбінацією IP-адреси (v4 або v6, залежно від протоколу, який ви використовуєте) та порту.

Коли сервер прослуховує з'єднання, він може повідомити ядро ​​про те, що він хотів би прослухати конкретну IP-адресу та порт, тобто одну TCP-адресу, або на одному і тому ж порті на кожній з IP-адрес хостів (як правило, вказано з IP-адресою IP-адреси) 0.0.0.0), який ефективно прослуховує багато різних «TCP - адреси» (наприклад, 192.168.1.10:8000, 127.0.0.1:8000і т.д.)

Ні, у вас не може прослуховувати дві програми на одній "TCP-адресі", тому що, коли надходить повідомлення, як ядро ​​дізнається, якій програмі надіслати це повідомлення?

Однак у більшості операційних систем ви можете встановити кілька IP-адрес на одному інтерфейсі (наприклад, якщо у вас є 192.168.1.10інтерфейс, ви також можете налаштувати його 192.168.1.11, якщо ніхто інший в мережі не використовує його), і в цих випадках ви може мати окремі програми, які прослуховують порту 8000на кожному з цих двох IP-адрес.


2

Якщо принаймні один із віддалених IP-адрес уже відомий, статичний і призначений для розмови лише з одним із ваших додатків, ви можете скористатися правилом iptables (таблиця nat, ланцюг ПЕРЕДАЧА) для перенаправлення вхідного трафіку з цієї адреси на "загальний" локальний порт на будь-який інший порт, де відповідна програма насправді слухає.


1

Так і ні. Лише одна програма може активно слухати порт. Але ця програма може заповідати її підключення до іншого процесу. Таким чином, ви можете мати кілька процесів, що працюють на одному порті.


@trusktr, я думаю, він мав на увазі це
warvariuc

1

Так.

З цієї статті:
https://lwn.net/Articles/542629/

Нова опція socket дозволяє декільком розеткам на одному хості прив’язуватися до одного порту


1
Приємне посилання, однак не пишеться там цей рядок - варіант SO_REUSEPORT нестандартний
Сахіл Сінгх

0

Якщо під програмами ви маєте на увазі кілька процесів, то так, але загалом НІ. Наприклад, сервер Apache запускає декілька процесів на одному і тому ж порту (як правило, 80). Це робиться шляхом позначення одного з процесів, щоб фактично прив’язатись до порту, а потім використовувати цей процес для передачі вручну різних процесів, які приймають з'єднання.


0

Ви можете змусити дві програми прослуховувати один і той же порт в одному мережевому інтерфейсі.

Для вказаного мережевого інтерфейсу та порту може бути лише одна розетка для прослуховування, але цей сокет може бути спільним між кількома програмами.

Якщо у вас є розетка для прослуховування в процесі подання заявки, а ви forkцей процес, сокет передається у спадок, тому технічно зараз два процеси будуть прослуховувати один і той же порт.


0

Я спробував таке socat:

socat TCP-L:8080,fork,reuseaddr -

І хоча я не зробив з'єднання з сокетом, я не можу двічі прослуховувати один і той же порт, незважаючи на reuseaddrможливість.

Я отримую це повідомлення (якого я очікував раніше):

2016/02/23 09:56:49 socat[2667] E bind(5, {AF=2 0.0.0.0:8080}, 16): Address already in use

0

Просто поділитися тим, що згадував @jnewton. Я запустив nginx і вбудований процес tomcat на своєму mac. Я бачу, як обидва процеси працюють у 8080 році.

LT<XXXX>-MAC:~ b0<XXX>$ sudo netstat -anp tcp | grep LISTEN
tcp46      0      0  *.8080                 *.*                    LISTEN     
tcp4       0      0  *.8080                 *.*                    LISTEN   

-2

Коротка відповідь:

Йдемо за даною тут відповіддю . Ви можете прослуховувати дві програми на одній і тій же IP-адресі та номері порту, тому довгий один порт - це порт UDP, а інший - порт TCP.

Пояснення:

Поняття порту є релевантним на транспортному шарі стеку TCP / IP, таким чином, доки ви використовуєте різні протоколи транспортного рівня стека, ви можете мати кілька процесів прослуховування в одній <ip-address>:<port>комбінації.

Одно сумніви у людей є, якщо два додатки працюють на одній <ip-address>:<port>комбінації, як клієнт, який працює на віддаленій машині, розрізнятиме їх? Якщо ви подивитеся на заголовок пакету IP-шару ( https://en.wikipedia.org/wiki/IPv4#Header ), ви побачите, що біти 72 до 79 використовуються для визначення протоколу, саме так можна розрізнити.

Якщо ви хочете мати дві програми на одній <ip-address>:<port>комбінації TCP , відповідь - ні. Цікавою вправою буде запустити два VM, дати їм однакову IP-адресу, але різні MAC-адреси, і подивіться, що станеться - ви помітите, що кілька разів VM1 отримає пакети, а в інший раз VM2 отримає пакети - залежно від оновлення кешу ARP).

Я відчуваю, що, зробивши два додатки, які працюють на одній і тій же, <op-address>:<port>ви хочете досягти певного балансування навантаження. Для цього ви можете запускати програми на різних портах і писати правила таблиці IP для роздрібнення трафіку між ними.

Також дивіться відповідь @ user6169806

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.