Может ли Python выбрать какой сетевой адаптер при открытии сокета? - PullRequest
16 голосов
/ 09 декабря 2011

На целевой машине, на которой запущено приложение python, будут доступны три сетевых интерфейса. В целом все три сети будут сильно различаться, однако существует вероятность, что две из трех могут быть в одинаковых сетях.

В приведенном ниже примере у меня нет контроля над адресом назначения на ETH 2 (поскольку это предварительно сконфигурированная система), поэтому я вынужден был выбрать, какой адаптер использовать программно.

Я вполне уверен, что это будет зависеть от того, как ОС работает с маршрутизацией соединений. Я надеюсь, что будет найден независимый от платформы способ решения проблемы с использованием Python, поскольку существует вероятность того, что это приложение должно будет работать как на Windows 7, так и на компьютере с Linux.

Пример кода

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.0.2', 8000)) # Which device will this connect to??

Нормальный регистр

  • ETH 0 Источник: 192.168.0.1
  • ETH 0 Пункт назначения: 192.168.0.2
  • ETH 1 Источник: 10.20.30.1
  • ETH 1 Пункт назначения: 10.20.30.2
  • ETH 2 Источник: 60.50.40.1
  • ETH 2 Пункт назначения: 60.50.40.1

Возможные проблемы

  • ETH 0 Источник: 192.168.0.1
  • ETH 0 Пункт назначения: 192.168.0.2
  • ETH 1 Источник: 10.20.30.1
  • ETH 1 Пункт назначения: 10.20.30.2
  • ETH 2 Источник: 192.168.0.3
  • ETH 2 Пункт назначения: 192.168.0.2

Дополнительная информация
Все адаптеры ETH0,1 и 2 подключены к разным физическим сетям

Ответы [ 3 ]

19 голосов
/ 09 декабря 2011

Я не могу много говорить о Windows, но в Linux интерфейс обычно не выбирается до тех пор, пока не будет принято решение о маршрутизации, поэтому вы обычно не можете сказать, на каком интерфейсе выходят ваши пакеты.

У вас есть возможность использовать SO_BINDTODEVICE (см. man 7 socket) в Linux.Это привязывает сокет к устройству, однако, только root может установить эту опцию для сокета.


Только что отмечен, и библиотека сокетов python не определила SO_BINDTODEVICE, но вы ее получитеот socket.h:

# from socket.h
# define SO_BINDTODEVICE 25

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, 25, 'eth0')

См. также:

14 голосов
/ 09 декабря 2011

В Windows, если вы знаете IP-адрес интерфейса, который хотите использовать, просто подключитесь к нему перед подключением.В Linux используйте опцию сокета SO_BINDTODEVICE в соответствии с предложением JimB (кажется, это тоже привилегированный вызов).

, т. Е. В Windows

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.0.1', 0))
s.connect(('...'))

Привязка адреса источника в Windows, выбор интерфейса с помощьютот же IP-адрес, что и у этого устройства, даже если этот IP-адрес имеет более высокую стоимость метрики маршрутизации.Это не работает в Linux, так как всегда перезаписывает исходный адрес IP-адресом выбранного устройства.Маршрутизация осуществляется исключительно на основании адреса назначения.Единственное исключение - если вы установили адрес источника на 127.0.0.1, то Linux не позволяет этим пакетам выходить из этого ящика.

0 голосов
/ 09 декабря 2011

SO_BINDTODEVICE звучит разумно, но обычно вы косвенно выбираете устройство по тому IP-адресу, с которым вы связываетесь. Чаще всего вам просто нужно связать с '', чтобы связать со всеми адресами машины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...