0

there is a similar question here, but no clear answers.

I need to be able to listen on one port (9000), and send to other servers on different ports (7777,8888,9999).

The code I wrote does work, but I'm not sure if it is the best method. It looks non-pythonic to continually use self.factory.factoryObjectList. I wish I could assign this to another value to clean up the code a little.

Is my method overkill? Can this be done in an easier way?

import sys
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, ClientFactory, ServerFactory
from twisted.protocols.basic import LineReceiver
from twisted.python import log

class RX_Protocol(LineReceiver):

    def dataReceived(self, data):
        self.sendMessageToConnections(self.factory.factoryObjectList, data)
        self.transport.write('sent \'%s\' to %d servers\n' % (data.strip(), self.countConnections(self.factory.factoryObjectList)))

    def connectionMade(self):
        self.transport.write('hello telnet user! Let\'s send a message to all connections\n')

    def sendMessageToConnections(self, factoryObjectList, data):
        for factoryObject in factoryObjectList:  # iterate through list of factory objects, 1 for each server
            for connection in factoryObject.factory.connections:  # now iterate through the actual connections of each factory
                connection.transport.write(data)

    def countConnections(self, factoryObjectList):
        counter = 0
        for factoryObject in factoryObjectList:
            if factoryObject.state == 'connected':
                counter += 1
        return counter


class RX_Factory(ServerFactory):
    protocol = RX_Protocol

    def __init__(self, factoryObjectList):
        self.factoryObjectList = factoryObjectList


## TX Stuff ##
class TX_Protocol(Protocol):

    def connectionMade(self):
        self.factory.connections.append(self)

    def connectionLost(self, reason):
        self.factory.connections.remove(self)


class TX_Factory(ClientFactory):  # subclass your factory of choice (Factory, ClientFactory, ServerFactory)
    protocol = TX_Protocol

    def __init__(self):
        self.connections = []

# spawn these in new terminals using nc -l XXXX
servers = [('localhost', 7777),
           ('localhost', 8888),
           ('localhost', 9999)]
# servers = [('localhost', 7777)]  # easier than opening 3 terminals

factoryObjectList = []  # will hold the multiple factories we use to connect to servers

# give us better STDOUT twisted logging
log.startLogging(sys.stdout)

for host, port in servers:
    factoryObjectList.append(reactor.connectTCP(host, port, TX_Factory()))

reactor.listenTCP(9000, RX_Factory(factoryObjectList))  #RX_Factory now "knows" about connections to servers
reactor.run()
Community
  • 1
  • 1
Jared
  • 607
  • 1
  • 6
  • 28
  • "non-pythonic", "overkill", "clean up" are all vague, subjective ways to describe a problem. Describe what you think is actually *wrong* with the code or you're not very likely to get answers that tell you how to do something right. – Jean-Paul Calderone May 07 '14 at 22:17
  • This question appears to be off-topic because it is about working code - it should probably be migrated to http://codereview.stackexchange.com – Simon MᶜKenzie May 08 '14 at 00:52
  • Thanks for the feedback. Should have been clearer. Very new to async code and twisted. – Jared May 08 '14 at 01:03

1 Answers1

1

Your method looks typical to me.

Take a look at SO: What is the correct way to access a protocols transport in Twisted? (which also links to another SO: Persistent connection in Twisted) there is a note about the newer "endpoint" system, you might like its style better.

Community
  • 1
  • 1
Mike Lutz
  • 1,812
  • 1
  • 10
  • 17