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

Ada*_*wis 17 python sockets linux windows

运行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??
Run Code Online (Sandbox Code Playgroud)

正常情况

  • 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都连接到不同的物理网络

Jim*_*imB 19

对于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')
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 您可以使用 socket.SO_BINDTODEVICE 而不是“25”的原始值 (3认同)

小智 15

在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(('...'))
Run Code Online (Sandbox Code Playgroud)

在Windows下绑定源地址,选择与该设备具有相同IP地址的接口,即使该IP地址具有更高的路由度量标准成本.但这在Linux下不起作用,因为它总是用所选设备的IP地址覆盖源地址.仅基于目的地地址完成路由.似乎唯一的例外是如果将源地址设置为127.0.0.1,则Linux会阻止这些数据包离开该框.

  • 地址是系统范围的,绑定到特定地址不会选择数据包离开的接口。该决定是在路由期间做出的。 (2认同)
  • 问题是如何选择“ bind”不起作用的网络适配器。Bind设置套接字的地址/端口,仅此而已。接收数据包的接口很可能是您想要的接口,但是您的传出数据包将通过路由期间确定的接口离开,通常是具有默认GW的接口。 (2认同)