1

我有一台可能位于多个防火墙后面的计算机,只有一个私有 IP……几乎无法从外部世界访问。

该计算机定期将 UDP 数据发送到远程服务器(可从任何地方访问)。该远程服务器可能与 UDP 发送方/客户端位于不同的网络中(或与该问题不同的国家/地区)。

在某个时刻,我必须发送一个包,确认我收到了一些数据,返回给“无法访问”的计算机,这意味着:客户端开始了通信并且我确实有一个套接字。

我害怕答案,因为我读到的 UDP 协议主要是send-->disconnect-->forget about the package,但问题来了。有什么方法可以使用现有的 UDP 套接字发送数据?

作为服务器,我使用了一个非常简单的 SocketServer 类:

class MyUDPHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        message_type = message_utils.extract_type(self.request[0])
        message_cls = message_factory.get_class_by_message_type(message_type)
        message = message_cls(
                              data=self.request[0],
                              came_from=self.client_address)
        print "Got %s" % message
        message.process()
        self.request[1].send("test") 

if __name__ == "__main__":
    SERVER_HOST = settings.SERVER_HOST\
                        if hasattr(settings, "SERVER_HOST") else ""
    SERVER_PORT = int(settings.SERVER_PORT)
    server = SocketServer.UDPServer(
                                    (SERVER_HOST, SERVER_PORT),
                                    MyUDPHandler)
    server.serve_forever()

该行self.request[1].send("test")因错误而失败:[Errno 89] Destination address required我阅读的越多,我就越认为我无法将数据发送回客户端,至少不能使用这个简单的“ send”解决方案。

我无法更改客户端。有没有办法重用套接字发送 UDP 数据?也许那里有一个我不知道的“救世主”课程?任何提示将不胜感激。

先感谢您。

4

2 回答 2

5

您必须像这样使用.sendto(),而不是.send()

self.request[1].sendto(
  "test",
  self.client_address) 

参考:http ://docs.python.org/2/library/socketserver.html#socketserver-udpserver-example


附加功能:

我可以创建的最小的响应式 UDP 套接字服务器:

import SocketServer
class MyUDPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.request[1].sendto( "test\n", self.client_address)
SocketServer.UDPServer( ("", 5432), MyUDPHandler).serve_forever()

因此,它可以从 Linux 命令行进行测试:

$ nc -u 127.1 5432

于 2013-04-18T16:30:01.400 回答
1

虽然从客户端和服务器的角度来看,UDP 是无连接的,但从 NAT/路由器的角度来看,存在一个为双向通信而维护的连接。服务器只需要回复它收到消息的 IP/端口即可到达客户端。

python 文档有一个很好的例子:http ://docs.python.org/2/library/socketserver.html#socketserver-udpserver-example

基本上它只需要请求地址并使用 sendto 功能

socket.sendto("test", self.client_address)
于 2013-04-18T16:30:25.230 回答