Savir
Savir

Reputation: 18438

UDP Socketserver - send data through same socket (impossible?)

I have a computer that may be behind several firewalls, have only a private IP... pretty much not reachable from the outside world.

That computer periodically sends UDP data to a remote server (accessible from everywhere). That remote server will probably be in a different network than the UDP sender/client (or in a different country from that matter).

At a certain point, I have to send a package acknowledging that I received some data back to the "unreachable" computer, meaning: the client started a communication and I do have a socket.

I am afraid of the answer, because of what I read of the UDP protocol being mainly send-->disconnect-->forget about the package, but here goes the question. Is there any way of sending data using an existing UDP socket?

As a server, I'm using a very simple SocketServer class:

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()

The line self.request[1].send("test") is failing with an error: [Errno 89] Destination address required and the more I read about it, the more I think I won't be able to send data back to the client, at least not with this simple "send" solution.

I can not change the client. Is there ANY way to send UDP data reusing a socket? Maybe there's a "savior" class out there I don't know about? Any hint will be appreciated.

Thank you in advance.

Upvotes: 1

Views: 4751

Answers (2)

Robᵩ
Robᵩ

Reputation: 168836

You must use .sendto(), not .send(), like this:

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

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


Extras:

The smallest responsive UDP socket server than I can create it this:

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

It can tested from a Linux command line thusly:

$ nc -u 127.1 5432

Upvotes: 5

kbickar
kbickar

Reputation: 624

Although from the client and server perspective, UDP is connectionless, from the NAT/router's perspective, there is a connection that is maintained for two way communication. The server just needs to reply to the IP/port that it received the message from to reach the client.

The python doc has a good example of this: http://docs.python.org/2/library/socketserver.html#socketserver-udpserver-example

Basically it just needs the request address and use the sendto function

socket.sendto("test", self.client_address)

Upvotes: 1

Related Questions