【问题标题】:How can you choose the network interface via which UDP broadcast packet is sent如何选择发送 UDP 广播数据包的网络接口
【发布时间】:2012-02-03 10:42:46
【问题描述】:

如果我像这样发送一个包含 'foo' 的 UDP 数据包:

socket = UDPSocket.new
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
socket.send('foo', 0, '<broadcast>', 40001)

然后wireshark告诉我数据包被正确发送,但不幸的是它的源地址是192.168.0.3。由于我的服务器正在监听 localhost:40001,这意味着它没有收到数据包。我不想让服务器监听 0.0.0.0,因为它不应该接收在另一个网络中发送的类似 UDP 请求。我可以让服务器在 192.168.0.0/24 网络中进行监听,但稍后它会从另一个网络进行监听,即既不是 localhost 也不是 192.168.0.0/24,所以这并不能解决问题。

有没有办法选择客户端套接字发送数据包的源地址(和接口)?

【问题讨论】:

    标签: ruby sockets networking udp


    【解决方案1】:

    我猜你正试图将它发送到环回设备,所以它应该是这样的(从来没有用 ruby​​ 尝试过):

    dev="lo"
    socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BINDTODEVICE, dev+'\0'))
    

    您可能还必须启用多播循环:

    socket.setsockopt(Socket::SOL_SOCKET, Socket::IP_MULTICAST_LOOP, [1].pack('i'))
    

    【讨论】:

    • 感谢您的建议。不幸的是,我不允许设置该选项。根据例如stackoverflow.com/questions/1207746/…,SO_BINDTODEVICE 需要 root 权限。我宁愿不以 root 身份运行应用程序。
    • uhm..然后监听0.0.0.0,根据ip地址过滤连接。
    • 那是后备计划:)。
    【解决方案2】:

    你试过bind()了吗?一般来说,如果您将socket.bind() 发送到某个地址(例如127.0.0.1),那么您的数据包应该来自该地址。环回和广播可能会受到特殊对待,但bind() 将是我尝试的首选。

    【讨论】:

    • 使用绑定有效,但这不是我的首选解决方案。这意味着我必须为我的客户端选择一个空闲端口,而您通常将其留给操作系统。这会带来额外的复杂性。
    • 啊,在阅读了一些额外的 C 示例后,我发现我可以安全地绑定到 'dummy' 端口 0。
    【解决方案3】:

    答案出现得太晚了两年,但这可能会对未来的 StackOverflow 用户有所帮助。看起来您需要使用套接字选项IP_MULTICAST_IF,它采用网络排序的 DWORD 版本的接口地址。幸运的是,ipaddr 库有一个实用的方法来转换人类可读的地址:

    address = '127.0.0.1'
    hton = IPAddr.new(address).hton
    socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_IF, hton)
    

    【讨论】:

      猜你喜欢
      • 2018-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-14
      • 1970-01-01
      • 2018-03-25
      • 2010-09-27
      • 1970-01-01
      相关资源
      最近更新 更多