Обычно только один процесс может прослушивать TCP-порт в Windows или любой другой ОС (по крайней мере, основных). В Windows вы ожидаете получить код ошибки 10048, если два процесса совместно используют порт. Это не будет применяться, если процессы привязаны к разным адресам интерфейса (даже если один привязан к INADDR_ANY
, а другой привязан к определенному адресу, они не конфликтуют). Кроме того, это не применяется, если SO_REUSEADDR
установлен на втором сокете.
Поскольку оба процесса привязаны к INADDR_ANY
, а вы утверждаете, что ваш процесс не имеет установленного SO_REUSEADDR
, это загадка. Насколько я могу судить, есть три возможности:
- Что-то в базовой библиотеке устанавливает
SO_REUSEADDR
по умолчанию.
- Второй сокет был фактически открыт позже, и это тот, который указывает
SO_REUSEADDR
.
- В слое сокетов Windows есть ошибка, которая позволила это сделать.
Я понимаю, что идеального программного обеспечения не существует, но я действительно не решаюсь выбрать третий вариант, особенно если вы можете легко воспроизвести его. Я бы посоветовал внимательно посмотреть вывод netstat
до и после запуска вашего процесса и посмотреть, существует ли другой слушатель до этого. Кроме того, попробуйте определить другой процесс и посмотреть, связан ли он (для этого вы можете включить столбец PID в диспетчере задач).
ИЗМЕНИТЬ
Комментатор ниже напомнил мне, что я должен указать, что поведение SO_REUSEADDR
действительно отличается на разных платформах. Windows позволяет новым сокетам принудительно привязываться к тому же порту, что и другие сокеты прослушивания, с неопределенным поведением, если оба сокета являются TCP, как обсуждалось здесь. На практике второй сокет, вероятно, «крадет» адрес, но официальная линия, по-видимому, такова, что поведение не определено:
Как только второй сокет успешно связан, поведение всех сокетов, связанных с этим портом, становится неопределенным. Например, если все сокеты на одном и том же порту предоставляют службу TCP, нельзя гарантировать, что любые входящие запросы на TCP-соединение через порт будут обработаны правильным сокетом — поведение недетерминировано.
Linux (и другие варианты Unix) не позволит двум сокетам TCP использовать один и тот же порт, если старый все еще прослушивает. В этом случае SO_REUSEADDR
разрешает связывание нового сокета только в том случае, если старый находится в состоянии TIME_WAIT (и, возможно, в состояниях FIN_WAIT и CLOSE_WAIT, мне нужно это проверить).
Кроме того, я нашел разницу в поведении довольно удивительной, когда впервые столкнулся с ней в Windows, но я проверил ее сам, и, конечно же, если вы установите SO_REUSEADDR
на обоих сокетах, вполне возможно, что успешно привязаться к точно такому же адресу и порту одновременно. Однако я не проводил тщательного тестирования точного поведения в этой ситуации, поскольку в моем случае это не имело большого значения.
Я не собираюсь указывать, какая платформа является «правильной», но, безусловно, поведение Windows привело к проблемам с безопасностью, поэтому они придумали опцию SO_EXCLUSIVEADDRUSE
для предотвращения принудительной привязки других сокетов. Я также, кажется, придерживаюсь мнения, что версию для Windows следует рассматривать как совершенно другой вариант с другим поведением, который просто имеет то же имя.
person
Cartroo
schedule
02.02.2013
setReuseAddress
? - person David Schwartz   schedule 26.11.2012SO_REUSEADDR
, поэтому такое поведение все еще вызывает недоумение, поскольку OP утверждает, что не указал эту опцию. Смотрите мой ответ для более подробной информации. - person Cartroo   schedule 02.02.2013