【问题标题】:All interfaces not being used despite multiple sockets尽管有多个套接字,但所有接口均未使用
【发布时间】:2020-01-12 04:01:54
【问题描述】:

尽管将两个 UDP 套接字绑定到主机不同接口上的 2 个不同地址,但流量仍流经单个接口。

网络拓扑如下: h2 和 s1 之间的 2 个链接 h1 和 s1 之间有 1 个链接

 ________
|        |
h2       s1_______h1
|________|

我在 mininet 上模拟 2 台主机和 1 台交换机。 h1 在 10.0.0.1:4243 运行 UDP 服务器。另一台主机有 2 个接口,ips 10.0.0.2 & 10.0.0.4 。我在 h2 上制作 2 个套接字,将一个绑定到 (10.0.0.2,9999) 并将另一个套接字绑定到 (10.0.0.4,8888)。我正在运行下面的代码,它应该在两个接口上交替发送数据包。

相反,第一个数据包在两个接口上发送。所有后续数据包都通过单个接口发送。

客户端代码(在 h2 上运行)

def client():
    sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock1.bind(("10.0.0.2",9999))

    sock2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock2.bind(("10.0.0.4",8888))

    while True:
        text = 'The time is {}'.format(datetime.now())
        data = text.encode('ascii')

        sock1.sendto(data, ('10.0.0.1', 4243))
        data, address = sock1.recvfrom(MAX_BYTES)

        sock2.sendto(data, ('10.0.0.1', 4243))
        data, address = sock2.recvfrom(MAX_BYTES)

服务器代码(在 h1 上运行)

def server():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('10.0.0.1', 4243))
    print('Listening at {}'.format(sock.getsockname()))
    while True:
        data, address = sock.recvfrom(MAX_BYTES)
        text = data.decode('ascii')
        print('The client at {} says {!r}'.format(address, text))
        text = 'Your data was {} bytes long'.format(len(data))
        data = text.encode('ascii')
        sock.sendto(data, address)

一个数据包通过 h2 的两个接口发送。后续数据包都只能通过 IP 10.0.0.2 的接口发送和接收。在 Wireshark 上,一半的数据包的 src/dest IP 设置为 10.0.0.4

【问题讨论】:

  • 你能在 h1 上显示ip route show 和 'cat /proc/sys/net/ipv4/ip_forward' 的输出吗?
  • ip route show : 10.0.0.0/8 dev h1-eth0 proto kernel scope link src 10.0.0.1
  • 猫 ip_forward : 1
  • 我需要 h2 的输出,我想你给了 h1
  • 您遇到了 TCP/IP 的“弱端系统模型”。

标签: python sockets network-programming udp mininet


【解决方案1】:

从你们的 cmets 来看,我认为正在发生的事情是这样的:

  1. 您的默认路由有冲突
  2. 您启用了允许内部路由的 ip_forwarding
  3. 由于#1 和#2,绑定调用基本上被否定了

默认路由冲突

从您的 cmets 来看,这两个接口可能都有 /8。这意味着对于 h2,内核为两者添加了相同的路由,例如:

10.0.0.0/8 dev h2-eth0 proto kernel scope link src 10.0.0.2 
10.0.0.0/8 dev h2-eth1 proto kernel scope link src 10.0.0.4 

这意味着内核只想选择其中一个来发送所有 10.0.0.0/8 流量到/从。您正在尝试通过绑定调用来解决此问题,但我不相信 Bind 会覆盖路由表行为。

ip_forwarding

如果设置了这个标志,它也会使事情变得复杂,因为它可能允许通过 eth0 的 eth1 流量。

绑定

因此,将所有这些结合在一起,您将套接字绑定到与各个接口相关联的各个 IP,但内核只想将发往 10.0.0.1 的流量路由到一个接口并选择 eth0。我认为通常这会阻止 eth1 流量,但由于路由和 ip_forward 标志,eth1 流量通过 eth0 路由(在初始 ARP 数据包之后,您看到的一个数据包)。

解决方案

给h1的接口两个IP地址10.1.0.1/16和10.0.0.1/16。然后给 h2-eth0 ip 地址 10.0.0.2/16 和 h2-eth1 ip 地址 10.1.0.2/16。然后让你的程序从 10.1.0.2 向 10.1.0.1 发送数据,从 10.0.0.2 向 10.0.0.1 发送数据。

通过隔离子网,您可以防止混淆的根本原因,即路由冲突。

【讨论】:

  • 如何将 2 个 IP 分配给同一个接口?
  • 最简单的方法是输入 'ip addr del 10.0.0.1/8 dev eth0' 删除现有的 ip 然后 'ip addr add 10.1.0.1/16 dev eth0' 和 'ip addr add 10.0.0.1/16 dev eth0' 添加两个 IP。网络管理员有可能会反对这种变化,如果你没有看到那些带有“ip show addr”的 IP,你需要通过 NM 查找如何做到这一点
猜你喜欢
  • 2019-02-26
  • 2018-09-09
  • 2022-01-20
  • 1970-01-01
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 2018-10-25
相关资源
最近更新 更多