Search code examples
pythontwisteddht

DHT TCP API using UDP internally to serve requests (twisted)


Not sure if this is the right title for my problem, but here it goes: I am currently implementing a Distributed Hash Table (DHT) with an API which can be contacted through TCP. It can serve multiple API calls like PUT, GET, Trace, while listening on multiple IP/Port combinations like this:

factory = protocol.ServerFactory()
factory.protocol = DHTServer
for ip in interfaces:
    for port in ports:
        reactor.listenTCP(int(port), factory, interface=ip)
        print ("Listening to: "+ ip +" on Port: "+port)
reactor.run() 

Now those "external" API calls are going to be executed by the underlying DHT implementation (Kademlia, Chord or Pastry). Those underlying DHT implementations are using different protocols to communicate with one another. Kademlia for example uses RPC through UDP.

The protocol for the TCP API (DHTServer in the Code above) has an internal DHT protocol like this:

self.protocol = Kademlia(8088, [("192.168.2.1", 8088)])

Now if a client makes two seperate API requests after one another i get this error message on the second request:

line 197, in _bindSocket
raise error.CannotListenError(self.interface, self.port, le)
    twisted.internet.error.CannotListenError: Couldn't listen on any:8088: [Errno 10
    048] Normalerweise darf jede Socketadresse (Protokoll, Netzwerkadresse oder Ansc
    hluss) nur jeweils einmal verwendet werden.

Which basically says that each socket address is only to be used once. I am not quite sure, but i guess it is because for each API request a new DHTServer protocol instance is created, which in turn also creates a new Kademlia instance and both are trying to listen on the same address. But why is this the case? Shouldn't the first DHTServer protocol instance be destroyed after the first request is served? What am i doing wrong? Is there a better way of doing this? I only recently started working with twisted, so please be patient. Thanks a lot!


Solution

  • My solution to this was to write my own Factory with the inner protocol already pre-defined. Thus i can access it from every instance and it stays the same.