2 Процессы, прослушивающие один и тот же порт -.NET not throwing exception
На приведенном ниже рисунке показаны 2 процесса, которые пытались и успешно связали сокеты-сокеты (сервер) с портом 10000 на моем локальном компьютере:
![Sysinternals showing 2 binds on port 10000]()
и здесь вывод netstat (для подтверждения):
netstat -a -n | find "10000"
TCP 0.0.0.0:10000 0.0.0.0:0 LISTENING
TCP 0.0.0.0:10000 0.0.0.0:0 LISTENING
TCP [::]:10000 [::]:0 LISTENING
(NB: процесс javaw.exe был первым, кто открыл сокет для прослушивания на 10000).
Пока я знаю ситуации, при которых несколько процессов могут прослушиваться на одном и том же порту (SO_REUSEADDR
), есть определенные вещи, которые мешают мне в моем конкретном сценарий:
-
В моем приложении я специально говорю .NET, что я хочу эксклюзивное сокет прослушивания (SO_EXCLUSIVEADDRUSE
) через
listener = new TcpListener(adr, ipport);
listener.ExclusiveAddressUse = true;
-
.NET делает not выдачу каких-либо исключений/ошибок/уведомлений о том, что порт уже используется. На самом деле, он на самом деле считает, что все прошло хорошо.
-
Моя серверная программа никогда не просыпается от вызова listener.AcceptTcpClient()
с этого момента. Клиентское приложение, которое должно взаимодействовать с сервером, получает действительное соединение, но не может связываться с "моим" сервером (предположительно потому, что оно устанавливает соединение с "другим" процессом, который не говорит о его "протоколе" ).
В случае, если кто-то хочет попытаться воспроизвести мои выводы: Второй процесс - это выпуск Helix для Eclipse (PHP). Но конкретный процесс не должен иметь значения здесь: если один процесс может делать странные вещи под ОС, так что другие могут.
Любые советы о том, как я могу либо получить ошибку, либо вообще предотвратить такую ситуацию (с помощью дополнительных параметров)?
Ответы
Ответ 1
Ссылка MSDN, опубликованная в вашем комментарии, кажется, отвечает на ваш вопрос.
Это связано с привязкой Java-приложения к конечной точке подстановочного IP-адреса (0.0.0.0
ip4; ::
для ip6 или IPEndpoint.ANY
). Я предполагаю, что переменная adr
в вашем фрагменте кода выше - это определенный IP-адрес, а не адрес подстановки.
Взгляните на таблицы в этой статье. В нем перечислены результаты попыток привязки к определенной или конечной точке шаблона во второй раз с различными комбинациями параметров сокета.
Короче говоря, код Java является обязательным для конечной точки подстановки 0.0.0.0
без опции сокета SO_EXCLUSIVEADDRUSE
. Матрица показывает, что когда это произойдет, вы можете успешно привязать к конкретному адресу и передать запрос на использование исключительного адреса.
Если вы должны были попытаться связать с подстановочным знаком, таблица показывает, что вызов завершился неудачно.
Ответ 2
Не уверен, почему он не выбрасывает исключение. Хотя, как говорят docs, конструктор TcpListener
действительно не проверяет, открыт или нет порт, и поэтому он вызывает только ArgumentException
, когда номер порта недействителен. Другие методы, такие как Start
, будут бросать SocketException
с ErrorCode
на WSAEADDRINUSE
(10048), когда порт уже открыт другим процессом (см. Метод запуска и Коды ошибок Socket).
Чтобы предотвратить это, вызовите Start
и поймайте SocketException
или используйте пространство имен System.Net.NetworkInformation
для запроса всех используемых портов и выясните, доступен ли определенный порт, как в этом ответе: В С#, как проверить, доступен ли порт TCP?
Ответ 3
Я считаю, что вам нужно фактически разрешить совместное использование TCP-порта. Сейчас я нахожусь на своем телефоне, поэтому лучше всего на данный момент добавить ссылку:
Общий доступ к портам Net.TCP
Ответ 4
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.exclusiveaddressuse.aspx - Обратите внимание на некоторые отличия ОС относительно ExclusiveAddressUse. Попробуйте запустить как администратор. Еще одна мысль, попробуйте войти в Управление компьютерами → Услуги и остановите службу обмена портами Net.Tcp.