Search code examples
pythonnetwork-programmingtcptwisted

Multiple call/response messages between Twisted server/client


I have a basic server and client implemented in Twisted. My goal is to have the client process some data, report its progress back to the server, and repeat until all the data is processed. The client is able to send an initial message to the server but it is not receiving the server's response letting it know it is ok to start processing that data. Here is the code I have.

Server:

from twisted.internet import reactor, protocol

PORT = 9000

progress = 0

class MyServer(protocol.Protocol):

    def dataReceived(self, data):
        global progress
        print(data)
        if data != "Ready?":
            progress = int(data)
        self.transport.write("Got it.")
        self.transport.loseConnection()

    def connectionLost(self, reason):
        global progress
        if progress == 10:
            print("Completed.")
            reactor.stop()

class MyServerFactory(protocol.Factory):
    protocol = MyServer

factory = MyServerFactory()
reactor.listenTCP(PORT, factory)
reactor.run()

Client:

from twisted.internet import reactor, protocol
import time

HOST = 'localhost'
PORT = 9000

progress = 0

class MyClient(protocol.Protocol):

    def connectionMade(self):
        self.transport.write("Ready?")
        self.transport.loseConnection()

    def dataReceived(self, data):
        global progress
        progress += 1
        print(progress)
        self.transport.write(str(progress))
        self.loseConnection()

    def connectionLost(self, reason):
        global progress
        if progress == 10:
            print("Completed.")
            reactor.stop()

class MyClientFactory(protocol.ClientFactory):
    protocol = MyClient

factory = MyClientFactory()
reactor.connectTCP(HOST, PORT, factory)

reactor.run()

Solution

  • I figured out that my issue was that I was prematurely closing the connection. In some earlier testing I was trying to send multiple messages within the dataReceived function which were getting concatenated into a single message. This led me to believe that you must lose the connection for each message to go through. Rather, you simply need to let the function finish before sending another message. Here is the updated code that is working as intended.

    Server:

    from twisted.internet import reactor, protocol
    
    PORT = 9000
    
    progress = 0
    
    class MyServer(protocol.Protocol):
    
        def dataReceived(self, data):
            global progress
            print(data)
            if data != "Ready?":
                progress = int(data)
            self.transport.write("Got it")
            if progress == 10:
                self.transport.loseConnection()
    
        def connectionLost(self, reason):
            print("Completed.")
            reactor.stop()
    
    class MyServerFactory(protocol.Factory):
        protocol = MyServer
    
    factory = MyServerFactory()
    reactor.listenTCP(PORT, factory)
    reactor.run()
    

    Client:

    from twisted.internet import reactor, protocol
    import time
    
    HOST = 'localhost'
    PORT = 9000
    
    progress = 0
    
    class MyClient(protocol.Protocol):
    
        def connectionMade(self):
            self.transport.write("Ready?")
    
        def dataReceived(self, data):
            global progress
            progress += 1
            print(progress)
            self.transport.write(str(progress))
            if progress == 10:
                self.transport.loseConnection()
    
        def connectionLost(self, reason):
            print("Completed.")
            reactor.stop()
    
    class MyClientFactory(protocol.ClientFactory):
        protocol = MyClient
    
    factory = MyClientFactory()
    reactor.connectTCP(HOST, PORT, factory)
    
    reactor.run()