Почему я могу привязать два сокета к одному порту в Windows?

#windows #sockets #networking #tcp #network-programming

Вопрос:

Я только что обнаружил, что — в Windows 10 — я могу привязать два сокета к (предположительно) одному и тому же TCP-порту. Хитрость заключается в привязке одного сокета ко всем интерфейсам (0.0.0.0:12345), а другого-к локальному хосту.

Рассмотрим этот фрагмент Python для демонстрации:

 s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(("0.0.0.0", 12345))
s2.bind(("127.0.0.1", 12345))
 

Windows 10 с радостью принимает эту конфигурацию, в то время как в Linux это не удается Address already in use .

Я знаю, что сетевые стеки отличаются в этих операционных системах, но я не ожидал этой конкретной проблемы.

Проблема, с которой я сталкиваюсь, заключается в том, что в этом тесте используются некоторые устаревшие продукты, о которых я должен позаботиться, и мне интересно, есть ли способы сделать так, чтобы Windows не допускала эту множественную привязку.

Обновление: я забыл сформулировать свои вопросы:

  • Почему это так?
  • Есть ли способы изменить такое поведение?

Комментарии:

1. Чтобы избежать такого поведения в Windows, включите параметр SO_EXCLUSIVEADDRUSE сокет. Дополнительные сведения см. в разделе Использование SO_REUSEADDR и SO_EXCLUSIVEADDRUSE в MSDN.

2. Вау, большое спасибо @RemyLebeau. Я не знал об этом варианте. s.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) действительно решает проблему, представленную здесь.

3. Вы должны включить это в ответ, чтобы я мог дать вам кредиты.

4. По причинам, пока мне неизвестным, это не решает мою реальную, более сложную проблему. У меня есть mysqld, работающий на 0.0.0.0:<порт> и <порт> SO_EXCLUSIVEADDRUSE в процессе тестирования еще не вызывает сбой. Но это то, над чем я должен сейчас поработать более подробно.

5. Не берите в голову. Он работает по назначению. Раньше я не читал всю статью целиком. Я смотрел на таблицу, в которой показано поведение для XP и более ранних версий, но я не видел другой таблицы (в разделе «Повышенная безопасность сокетов»), которая показывает поведение в более новых версиях Windows, которое фактически позволяет вашему сценарию успешно выполнить 2-ю привязку, если обе привязки находятся под одной учетной записью пользователя, но не под разными учетными записями пользователей.