【问题标题】:How does a socket know which network interface controller to use?套接字如何知道要使用哪个网络接口控制器?
【发布时间】:2011-05-16 21:22:03
【问题描述】:

如果一台计算机有多个网卡,它们都连接到不同的网络并正常工作,当我们打开一个套接字时,操作系统如何确定该套接字使用哪个网卡?套接字 API 是否允许我们明确指定要使用的 NIC?

【问题讨论】:

    标签: sockets networking


    【解决方案1】:

    我是从 Linux 的角度来写这篇文章的,但我想它适用于所有地方。

    在绑定套接字时做出决定。当bind 被调用时,你指定的地址决定了套接字将监听的接口。 (甚至所有接口。)

    即使您不使用bind,它也会在您connect 时隐式发生。在路由表中查找目的地,该表必须包含到目的地网络的路由。路由还包含要使用的接口,甚至可以选择指定源地址。如果不指定源地址,则取接口的主地址。

    您实际上可以将bindconnect 一起使用,以强制您的传出 连接使用特定地址和端口。套接字必须始终具有这两位信息,因此即使您没有,也会使用主地址并选择随机端口。

    【讨论】:

    • "调用bind时,你指定的地址决定了socket监听的接口。" bind 如何确定这一点?如果您在同一个子网上有多个接口怎么办?
    • 如果我将套接字绑定到与任何接口都不匹配的 IP 地址怎么办?那么Kernel有做NAT吗?
    • 如果我在连接之前绑定了一个接口,这是否意味着传出流量的连接将使用我绑定的接口而不遵循路由决策?
    • @flow2k 当您bind() 到 IP 时,您将绑定到 IP 所属的特定接口。不能有多个具有相同 IP 的接口。
    • @abhiarora 如果 IP 不存在,bind() 将失败。
    【解决方案2】:

    我什至与此问题无关时,我不知道为什么我包含在编辑建议中。我之前也收到过类似的编辑建议..可能是一些错误/问题。

    (如果您愿意投票,@Shtééf 的回答比我的更值得。)

    这取决于你是连接还是绑定。

    如果你绑定,你可以绑定到与机器的一个接口对应的特定IP地址,或者你可以绑定到0.0.0.0,在这种情况下,套接字将监听所有接口。

    如果您连接一个未绑定的套接字,那么机器的路由表连同目标 IP 地址将确定连接请求在哪个接口发出。

    可以绑定一个套接字然后连接它。在这种情况下,套接字在建立连接时将根据绑定调用保持绑定。 (感谢@RemyLebeau 指出这一点。)

    【讨论】:

    • 除非在调用 connect() 之前调用 bind()。
    • @RemyLebeau 实际上这不一定是真的。在 TCP RFC 中有一个关于“强端和弱端系统模型”的长时间讨论,结论是 TCP 只需要“弱端”模型。您所说的仅适用于“强端”模型。
    • 我不知道“弱端”和“强端”指的是什么,但是我知道的每个支持套接字的平台都允许在客户端需要时在 connect() 之前调用 bind()为出站连接使用特定的 IP/适配器。如果没有事先调用bind()connect() 会决定使用哪一个。
    • @RemyLebeau 我不清楚。不一定正确的部分是暗示如果您绑定到特定接口,则连接请求将在该接口上发出。弱端系统模型允许情况并非如此。如果您不知道强端和弱端系统模型是什么,您可以随时查找它们。在 RFC 中。
    • 如果在连接前绑定了某个接口,则连接的本地地址被绑定,连接请求必须使用该接口,否则违反绑定。
    【解决方案3】:

    我不确定哪种方法最好,但是 Shtéf 提出的 bind()-before-connect() 方法有另一种理论。将 setsockopt() 与 SO_BINDTODEVICE 一起使用。见:http://codingrelic.geekhold.com/2009/10/code-snippet-sobindtodevice.html

    【讨论】:

      【解决方案4】:

      作为替代方法,您可以根据其名称搜索适当的 nic:

              //Find the ip address based on the ethernet adapter name. On my machine the ethernet adapter is "Ethernet"
              System.Net.NetworkInformation.NetworkInterface[] nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
              System.Net.NetworkInformation.NetworkInterface ethernet = nics.Where(n => n.Name.Equals("Ethernet")).Single();
              UnicastIPAddressInformation uniCastIPAddressInformation = ethernet.GetIPProperties().UnicastAddresses.Where(a => a.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).Single();
      
              IPEndPoint localEndPoint = new IPEndPoint(uniCastIPAddressInformation.Address, 9000);
      
              //Create a TCP/IP socket.  
              Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
              //Bind and start listening
              listener.Bind(localEndPoint);
              listener.Listen(10);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-09
        • 1970-01-01
        • 2011-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-02
        相关资源
        最近更新 更多