我试图在具有两个接口的系统上设置套接字的输出接口。我搜索了很多,我找到了不同的答案。有些人说我可以bind
在调用connect
之前选择一个特定的接口(如How does a socket know which network interface controller to use?中)。但其他人说这还不够(如http://codingrelic.geekhold.com/2009/10/code-snippet-sobindtodevice.html或How to open a socket on a specific interface and receive both IPv4 and IPv6 traffic)。
我使用SO_BINDTODEVICE
进行实施。但是,bind
解决方案之前的connect
无效。看起来源地址不会影响路由,在这种情况下只考虑路由表。有人说这是由Linux的弱端系统模型引起的。根据{{3}},源地址未指定输出接口。
如果可能的话,我希望有一个便携式解决方案。我知道SO_BINDTODEVICE
仅在Linux中可用。
答案 0 :(得分:2)
源地址不会影响数据包的路由。将根据目标地址和主机的路由器表选择接口。您可以使用route命令修改它。
route default gw [gateway IP]
无论套接字绑定哪个接口,都要根据路由表路由数据包。套接字绑定的接口将确定源IP地址。
现在,我运行一些绑定到loopback接口的测试,并将套接字连接到Internet中的其他地址,在这种情况下,连接失败了errno 22(EINVAL)。但是,在其他测试中有两个接口(没有环回),并且连接到Internet上的服务器,无论我将哪个接口绑定到套接字,数据包都是根据路由表发送的,在我的情况下是默认的规则。源地址取决于绑定。
答案 1 :(得分:0)
绑定是否影响路由取决于系统使用弱ES模型还是强ES模型的事实。 Linux使用弱ES模型,而所有基于BSD的系统(包括macOS)都使用强ES模型。 Windows在Vista之前使用弱ES模型,然后切换到强ES模型。
Microsoft关于该主题的页面非常详细,介绍了这两种模式以及绑定将如何影响这两种模式下的路由和数据包接收:
因此,在基于BSD的系统和Windows Vista及更高版本上,您可以使用bind选择接口,但不能在Linux上选择接口。在Linux上,您必须使用SO_BINDTODEVICE
。因此,支持这两种模式中的任何一种的解决方案都非常易于移植。
但是,有一个陷阱:如果系统允许多个接口可以具有相同的地址,则bind不会真正选择接口,而只会限制接口的选择。然后,通过查询路由表或通过某些系统特定的接口顺序来执行最终选择。