Python在打开套接字时可以选择什么网络适配器吗?



运行python应用程序的目标机器将有三个可用的网络接口。一般来说,这三个网络会有很大的不同,但是有可能三个网络中的两个会在相似的网络上。

在下面的例子中,我无法控制ETH 2上的目标地址(因为它是一个预配置的系统),因此我强制选择以编程方式使用的适配器。

我很确定这将取决于操作系统如何处理路由连接。我希望有一种独立于平台的方法来解决这个问题,因为这个应用程序有可能需要在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都连接到不同的物理网络

我不能为Windows说太多,但是在Linux上,接口通常是在路由决定做出之前才被选择的,因此您通常无法决定数据包离开哪个接口。

您确实可以选择在Linux上使用SO_BINDTODEVICE(参见man 7 socket)。这将一个套接字绑定到一个设备,但是,只有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')

参见:

  • Linux:如何强制使用特定的网络接口?
  • 我如何使一个出套接字到一个特定的网络接口?

在Windows上,如果您知道要使用的接口的IP地址,只需在连接之前绑定它。在Linux上,按照JimB的建议,使用套接字选项SO_BINDTODEVICE(似乎也是一个特权调用)。

。在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会阻止这些数据包从该盒子中发出。

SO_BINDTODEVICE听起来很合理,但通常您将通过绑定的IP地址间接选择设备。通常情况下,你会绑定到",绑定到机器的所有地址。

最新更新