【问题标题】:Does a UDP service have to respond from the connected IP address?UDP 服务是否必须从连接的 IP 地址响应?
【发布时间】:2010-11-21 12:23:15
【问题描述】:

Pyzor 使用 UDP/IP 作为通信协议。我们最近将公共服务器切换到一台新机器,并开始收到许多超时的报告。我发现如果我将查询的 IP 从eth0:1 更改为eth0,我可以解决这个问题。

我可以用一个简单的例子重现这个问题:

这是服务器代码:

#! /usr/bin/env python

import SocketServer

class RequestHandler(SocketServer.DatagramRequestHandler):
    def handle(self):
        print self.packet
        self.wfile.write("Pong")

s = SocketServer.UDPServer(("0.0.0.0", 24440), RequestHandler)
s.serve_forever()

这是客户端代码(188.40.77.206eth0188.40.77.236 是同一个服务器,但是是 eth0:1):

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.sendto('ping', 0, ("188.40.77.206", 24440))
4
>>> s.recvfrom(1024)
('Pong', ('188.40.77.206', 24440))
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.sendto('ping', 0, ("188.40.77.236", 24440))
4
>>> s.recvfrom(1024)
[never gets anything]

服务器在这两种情况下都会收到“ping”数据包(因此在两种情况下都会发送“pong”数据包)。

奇怪的是,这确实在某些地方有效(即我会从两个 IP 获得响应)。例如,它适用于188.40.37.137(相同的网络/数据中心,不同的服务器),也适用于89.18.189.160(不同的数据中心)。在这些情况下,recvfrom 响应确实具有eth0 IP,而不是所连接的 IP。

这只是UDP的规则吗?这是Python UDPServer 类的问题/限制吗?是我做错了什么吗?除了简单地连接到eth0 IP(或侦听特定 IP 而不是0.0.0.0)之外,我还有什么方法可以完成这项工作?

【问题讨论】:

    标签: python sockets udp ip multihomed


    【解决方案1】:

    我在使用 TFTP 服务器时遇到了这个问题。我的服务器有两个面向同一个网络的 IP 地址。由于 UDP 是无连接的,因此在这种情况下可能会出现 IP 地址未按预期设置的问题。我的顺序是:

    1. 客户端将初始数据包发送到特定 IP 地址的服务器
    2. 服务器从传入的数据包中读取客户端的源地址,并发送响应。
      1. 但是,在响应中,服务器的“源地址”是根据路由表设置的,它被设置为其他 IP 地址。
      2. 无法控制服务器的“源”IP 地址,因为操作系统没有告诉我们请求来自哪个 IP 地址。
    3. 客户端从“其他”IP 地址获得响应,并拒绝它。

    我的解决方案是专门将 TFTP 服务器绑定到我想监听的 IP 地址,而不是绑定到所有接口。

    我在Linux man page for tftpd(TFTP 服务器)中发现了一些可能相关的文本。这里是:

     Unfortunately, on multi-homed systems, it is impossible for tftpd to
     determine the address on which a packet was received. As a result, tftpd
     uses two different mechanisms to guess the best source address to use for
     replies. If the socket that inetd(8) passed to tftpd is bound to a par‐
     ticular address, tftpd uses that address for replies. Otherwise, tftpd
     uses ‘‘UDP connect’’ to let the kernel choose the reply address based on
     the destination of the replies and the routing tables. This means that
     most setups will work transparently, while in cases where the reply
     address must be fixed, the virtual hosting feature of inetd(8) can be
     used to ensure that replies go out from the correct address.  These con‐
     siderations are important, because most tftp clients will reject reply
     packets that appear to come from an unexpected address.
    

    请参阅this answer,这表明在 Linux 上可以读取传入 UDP 数据包的本地地址,并将其设置为传出数据包。在 C 中是可能的;不过,我不确定 Python。

    【讨论】:

    • 这听起来正是这里发生的事情。我写了一个 C 客户端,它和上面的 Python 做同样的事情,我仍然得到相同的结果,所以“来自其他 IP 的拒绝响应”必须发生在 C 库级别(这实际上意味着我被它困住了)。看起来我还需要绑定到特定地址。感谢您的帮助!
    【解决方案2】:

    这只是UDP的规则吗?

    没有。

    这是一个问题/限制与 Python UDPServer 类?

    怀疑。

    是不是我做错了什么?

    您的程序看起来正确。

    数据报没有到达服务器的原因有很多。 UDP 是无连接的,因此您的客户端只是将 ping 发送到以太网,而不知道是否有人收到它。

    查看是否允许您绑定到该地址。有一个很棒的小程序 netcat 非常适合低级别的网络访问。它并非总是在每个系统上都可用,但很容易下载和编译。

    nc -l -s 188.40.77.236 -p 24440 -u
    

    如果您像以前一样运行客户端程序,您应该会在终端上看到“Ping”字样。 (您可以键入 Pong 并将其设置回您的客户端。玩起来很有趣。)如果您得到 ping,则不是网络问题,而是 Python 服务器程序或库有问题。如果 ping 不通,则无法建立连接。 “请联系您的网络管理员寻求帮助。”

    要检查的内容包括...

    1. 防火墙问题?
    2. 别名网络接口的配置问题。
    3. 用户权限问题。

    【讨论】:

    • 问题不在于地址绑定,因为服务器得到了“ping”——但客户端没有得到“pong”。运行绑定到该 IP 的 netcat 可以工作(但 SocketServer 也可以)。运行绑定到 0.0.0.0 的 netcat 不起作用
    • 我编辑了这个问题,以便更清楚地表明问题在于响应,而不是接收客户端数据包的服务器。
    猜你喜欢
    • 2018-01-22
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    相关资源
    最近更新 更多