Могут ли два приложения прослушивать один и тот же порт?

283

Могут ли два приложения на одном компьютере связываться с одним и тем же портом и IP-адресом? Если сделать еще один шаг вперед, может ли одно приложение прослушивать запросы, приходящие с определенного IP, а другое - на другой удаленный IP? Я знаю, что у меня может быть одно приложение, которое запускает два потока (или ветвления) для одинакового поведения, но могут ли два приложения, которые не имеют ничего общего, делать то же самое?

nadiv
источник
2
Для подробного подробного ответа о повторном использовании адресов / портов с несколькими сокетами: stackoverflow.com/questions/14388706/…
Бьярке Фрейнд-Хансен,

Ответы:

248

Ответ зависит от того, какая ОС рассматривается. В общем, хотя:

Для TCP нет. Вы можете иметь только одно приложение, прослушивающее один и тот же порт одновременно. Теперь, если у вас есть две сетевые карты, вы можете заставить одно приложение прослушивать первый 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()этому порту другие сокеты , если к этому порту уже не подключен активный прослушивающий сокет. Это позволяет обойти эти сообщения об ошибках «Адрес уже используется» при попытке перезагрузить сервер после сбоя.

JNewton
источник
1
TCP + UDP теперь работает (достаточно новое ядро). Смотрите ссылку, которую я добавил к ответу.
ДПБ
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, и наоборот.

Ссылка: Стивенс и Райт, иллюстрированный TCP / IP, том II.

Маркиз Лорн
источник
у вас есть ссылка под рукой? Возможность сосуществования TCP-UDP - это мой вопрос. Заранее спасибо :)
Вольф
1
@ Волк Просто попробуй. Это все доказательства, которые вам действительно нужны. Я цитирую Стивенса и Райта: вы не можете стать намного лучше, чем это.
Маркиз Лорн
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 (), который создает новый файловый дескриптор, связанный с конкретным потоком, оставляя исходный дескриптор сервера свободным для получения новых подключений от клиентов
Javier
7
Этот ответ нельзя считать правильным. Он полностью игнорирует существование SO_REUSEADDR и SO_REUSEPORT.
маркиз Лорн
@ Хавьер Нет, это не так. Открытие порта с точки зрения серверного приложения происходит, когда вы привязываете прослушивающий сокет или, скорее, привязываете сокет, к которому собираетесь listen()подключиться. Скорее всего, вопрос заключается в том, чтобы открыть его в брандмауэре. Здесь слишком много ошибок, и все они исправлены за 7 лет. Ответ также исключает случай привязки к другому локальному адресу с одинаковым номером порта. Это на самом деле совершенно неверно.
Маркиз Лорн
27

Да, безусловно . Насколько я помню, начиная с версии ядра 3.9 (не уверен в версии) SO_REUSEPORTбыла введена поддержка. SO_RESUEPORTпозволяет привязку к одному и тому же порту и адресу, если первый сервер устанавливает эту опцию перед привязкой своего сокета.

Он работает как для TCP, так и для UDP . Обратитесь к ссылке для более подробной информации: SO_REUSEPORT

Примечание : принятый ответ больше не соответствует действительности, по моему мнению.

Piyush
источник
2
Полностью верно. Если это не так, как может работать Wireshark?
Staszek
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

Mitchbcn
источник
Есть ли такая программа на windows? Мне нужно, чтобы мой локальный сервер IIS и брокер ActiveMQ прослушивали порт 443
Харви Лин
3

Когда вы создаете TCP-соединение, вы запрашиваете подключение к определенному TCP-адресу, который представляет собой комбинацию IP-адреса (v4 или v6, в зависимости от используемого протокола) и порта.

Когда сервер прослушивает соединения, он может сообщить ядру, что он хочет прослушивать определенный IP-адрес и порт, т. Е. Один TCP-адрес, или на одном и том же порту на каждом из 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-адресов.

CJS
источник
2

Если хотя бы один из удаленных IP-адресов уже известен, статичен и предназначен для общения только с одним из ваших приложений, вы можете использовать правило iptables (таблица nat, chain PREROUTING) для перенаправления входящего трафика с этого адреса на «общий» локальный порт для любой другой порт, где на самом деле слушает соответствующее приложение.

Stemar
источник
1

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

Раджеш
источник
@trusktr, я думаю, он имел в виду это
warvariuc
1

Да.

Из этой статьи:
https://lwn.net/Articles/542629/

Новая опция сокетов позволяет нескольким сокетам на одном хосте связываться с одним и тем же портом

user6169806
источник
1
Хорошая ссылка, но не
Сахил Сингх,
0

Если под приложениями вы подразумеваете несколько процессов, то да, но, как правило, НЕТ. Например, сервер Apache запускает несколько процессов на одном и том же порту (как правило, 80). Это делается путем назначения одного из процессов фактическому связыванию с портом, а затем использования этого процесса для передачи обслуживания различным процессам, которые принимают соединения.

nitinsh99
источник
0

Два приложения могут прослушивать один и тот же порт на одном сетевом интерфейсе.

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

Если у вас есть прослушивающий сокет в процессе приложения, и вы forkэтот процесс, сокет будет унаследован, так что технически теперь будут два процесса, слушающие один и тот же порт.

warvariuc
источник
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 , ответ - нет (Интересным упражнением будет запуск двух виртуальных машин, присвоение им одинакового IP-адреса, но разных MAC-адресов, и посмотреть, что произойдет - вы заметите, что несколько раз VM1 получит пакеты, а в другой раз VM2 получит пакеты - в зависимости от обновления кэша ARP).

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

Также см. Ответ @ user6169806.

Сахил Сингх
источник