[Twisted-Python] How can I send unique configuration data for multiple connections through a factory?
Good day:
I've been having fun with Twisted. I have my application running fine, with
multiple server and client connections using Telnet. :-)
However, users always want something. I need to send some unique
configuration information to each connection. The connections are made
using connectTCP. My first attempt assumed that the connection was made
when the call to connectTCP was executed. It didn't work! :-(
-------------------------------
from twisted.internet.protocol import ClientFactory
from twisted.internet import reactor
from twisted.conch.telnet import StatefulTelnetProtocol
class testClient(StatefulTelnetProtocol):
def connectionMade(self):
self.title = self.factory.connectString
print "Client Connected: " + self.title
self.setRawMode()
self.factory.connections.append(self)
def connectionLost(self, reason):
if self in self.factory.connections:
self.factory.connections.remove(self)
def rawDataReceived(self,data):
print data + "\n"
class ClusterClientFactory(ClientFactory):
protocol = testClient
def __init__(self):
self.connections = []
self.connectString = ''
def startFactory(self):
print "startFactory: " + self.connectString
def startedConnecting(self, connector):
print "Started connecting: " + str(connector)
print self.connectString
def buildProtocol(self, addr):
print "bulldProtocol: " + str(addr)
print "buildProtocol: " + self.connectString
p = self.protocol()
p.factory = self
return p
if __name__ == '__main__':
def startUp():
factory = ClusterClientFactory()
factory.maxDelay = 120 # two minutes
factory.connectString = "FirstString..."
reactor.connectTCP("localhost", 7300, factory)
factory.connectString = "SecondString"
reactor.connectTCP("localhost", 7300, factory)
reactor.callWhenRunning(startUp)
reactor.run()
----------------------------------
The results are that buildProtocol gets the second string both times.
startedConnecting gets the correct string, but all I have there is a
connection object. I need the correct data in buildProtocol to do it this
way.
------------------------------------
C:\Users\Mark\src\play>python testclient.py
startFactory: FirstString...
Started connecting:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 If you create two instances of your ClusterClientFactory, each with a unique string, you should be fine. Requires only a small modification: factory = ClusterClientFactory() factory.maxDelay = 120 # two minutes factory.connectString = "FirstString..." reactor.connectTCP("localhost", 7300, factory) factory2 = ClusterClientFactory() factory2.maxDelay = 120 # two minutes factory2.connectString = "SecondString" reactor2.connectTCP("localhost", 7300, factory) You can clean this up by putting the maxDelay and connectString in the constructor of the factory: reactor2.connectTCP("localhost", 7300, ClusterClientFactory(120, "First")) reactor2.connectTCP("localhost", 7300, ClusterClientFactory(120, "Second")) Arjan Mark Bailey wrote:
Good day:
I've been having fun with Twisted. I have my application running fine, with multiple server and client connections using Telnet. :-)
However, users always want something. I need to send some unique configuration information to each connection. The connections are made using connectTCP. My first attempt assumed that the connection was made when the call to connectTCP was executed. It didn't work! :-(
-------------------------------
from twisted.internet.protocol import ClientFactory from twisted.internet import reactor from twisted.conch.telnet import StatefulTelnetProtocol
class testClient(StatefulTelnetProtocol):
def connectionMade(self): self.title = self.factory.connectString print "Client Connected: " + self.title self.setRawMode() self.factory.connections.append(self)
def connectionLost(self, reason): if self in self.factory.connections: self.factory.connections.remove(self)
def rawDataReceived(self,data): print data + "\n"
class ClusterClientFactory(ClientFactory):
protocol = testClient
def __init__(self): self.connections = [] self.connectString = ''
def startFactory(self): print "startFactory: " + self.connectString
def startedConnecting(self, connector): print "Started connecting: " + str(connector) print self.connectString
def buildProtocol(self, addr): print "bulldProtocol: " + str(addr) print "buildProtocol: " + self.connectString
p = self.protocol() p.factory = self return p
if __name__ == '__main__':
def startUp():
factory = ClusterClientFactory() factory.maxDelay = 120 # two minutes
factory.connectString = "FirstString..." reactor.connectTCP("localhost", 7300, factory)
factory.connectString = "SecondString" reactor.connectTCP("localhost", 7300, factory)
reactor.callWhenRunning(startUp) reactor.run()
----------------------------------
The results are that buildProtocol gets the second string both times. startedConnecting gets the correct string, but all I have there is a connection object. I need the correct data in buildProtocol to do it this way.
------------------------------------
C:\Users\Mark\src\play>python testclient.py startFactory: FirstString... Started connecting:
FirstString... Started connecting: SecondString bulldProtocol: IPv4Address(TCP, '127.0.0.1', 7300) buildProtocol: SecondString Client Connected: SecondString Welcome to SimpleServer5 bulldProtocol: IPv4Address(TCP, '127.0.0.1', 7300) buildProtocol: SecondString Client Connected: SecondString Welcome to SimpleServer5
--------------------------
My "best" idea is to pass the strings to the factory in a dictionary indexed by the IP address and the port. Then, buildProtocol() can use that to recover the string and I can use reactor.resolve() to translate the host name to the IP address. The real application won't have multiple connections to the same host and port like this example, so this would work.
There MUST be a better way. :-)
My "simpleserver" is below if you want to run this.
THANKS for all of your help. I have the basic application running now (including a Tkinter GUI :-) ) and Twisted has saved me hundreds or even thousands of lines of code...
Mark Bailey
------------------------------
from twisted.conch.telnet import StatefulTelnetProtocol from twisted.internet import reactor, protocol from twisted.protocols.basic import LineReceiver
class TelnetEcho(StatefulTelnetProtocol): def connectionMade(self): self.factory.connection.append(self) self.sendLine("Welcome to SimpleServer5\r\n")
def lineReceived(self, data): data = data.rstrip('\n\r')
if data.upper() == 'BYE': self.sendLine("Goodbye...\r") self.transport.loseConnection() else: self.sendLine("Unrecognized command: %r\r" % (data,))
def connectionLost(self, reason): self.factory.connection.remove(self)
class TelnetEchoFactory(protocol.Factory): protocol = TelnetEcho def __init__(self): self.connection = []
def createTelnetServer(port=7300): telnetinstance = TelnetEchoFactory() # needs to be a list reactor.listenTCP(port,telnetinstance)
if __name__ == "__main__": reactor.callWhenRunning(createTelnetServer) reactor.run()
------------------------------------------------------------------------
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAktzC0MACgkQigE4AbflYer9nwCgixra0FaTD6ubvGJufjApRG/m A34An3C2ng+4x3/halWSgGQUvQvsCiTM =Cg6W -----END PGP SIGNATURE-----
Thanks, Arjan. Of course, factories are breeding like rabbits, but that was
the obvious solution! :-) I wish I had thought of it.
You saved me several MORE hours...I've spend all day on this.
(It's snowing and work was CLOSED! Yeehah!)
Mark
On Wed, Feb 10, 2010 at 2:38 PM, Arjan Scherpenisse
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
If you create two instances of your ClusterClientFactory, each with a unique string, you should be fine. Requires only a small modification:
factory = ClusterClientFactory() factory.maxDelay = 120 # two minutes factory.connectString = "FirstString..." reactor.connectTCP("localhost", 7300, factory)
factory2 = ClusterClientFactory() factory2.maxDelay = 120 # two minutes factory2.connectString = "SecondString" reactor2.connectTCP("localhost", 7300, factory)
You can clean this up by putting the maxDelay and connectString in the constructor of the factory:
reactor2.connectTCP("localhost", 7300, ClusterClientFactory(120, "First")) reactor2.connectTCP("localhost", 7300, ClusterClientFactory(120, "Second"))
Arjan
Mark Bailey wrote:
Good day:
I've been having fun with Twisted. I have my application running fine, with multiple server and client connections using Telnet. :-)
However, users always want something. I need to send some unique configuration information to each connection. The connections are made using connectTCP. My first attempt assumed that the connection was made when the call to connectTCP was executed. It didn't work! :-(
-------------------------------
from twisted.internet.protocol import ClientFactory from twisted.internet import reactor from twisted.conch.telnet import StatefulTelnetProtocol
class testClient(StatefulTelnetProtocol):
def connectionMade(self): self.title = self.factory.connectString print "Client Connected: " + self.title self.setRawMode() self.factory.connections.append(self)
def connectionLost(self, reason): if self in self.factory.connections: self.factory.connections.remove(self)
def rawDataReceived(self,data): print data + "\n"
class ClusterClientFactory(ClientFactory):
protocol = testClient
def __init__(self): self.connections = [] self.connectString = ''
def startFactory(self): print "startFactory: " + self.connectString
def startedConnecting(self, connector): print "Started connecting: " + str(connector) print self.connectString
def buildProtocol(self, addr): print "bulldProtocol: " + str(addr) print "buildProtocol: " + self.connectString
p = self.protocol() p.factory = self return p
if __name__ == '__main__':
def startUp():
factory = ClusterClientFactory() factory.maxDelay = 120 # two minutes
factory.connectString = "FirstString..." reactor.connectTCP("localhost", 7300, factory)
factory.connectString = "SecondString" reactor.connectTCP("localhost", 7300, factory)
reactor.callWhenRunning(startUp) reactor.run()
----------------------------------
The results are that buildProtocol gets the second string both times. startedConnecting gets the correct string, but all I have there is a connection object. I need the correct data in buildProtocol to do it this way.
------------------------------------
C:\Users\Mark\src\play>python testclient.py startFactory: FirstString... Started connecting:
FirstString... Started connecting: SecondString bulldProtocol: IPv4Address(TCP, '127.0.0.1', 7300) buildProtocol: SecondString Client Connected: SecondString Welcome to SimpleServer5 bulldProtocol: IPv4Address(TCP, '127.0.0.1', 7300) buildProtocol: SecondString Client Connected: SecondString Welcome to SimpleServer5
--------------------------
My "best" idea is to pass the strings to the factory in a dictionary indexed by the IP address and the port. Then, buildProtocol() can use that to recover the string and I can use reactor.resolve() to translate the host name to the IP address. The real application won't have multiple connections to the same host and port like this example, so this would work.
There MUST be a better way. :-)
My "simpleserver" is below if you want to run this.
THANKS for all of your help. I have the basic application running now (including a Tkinter GUI :-) ) and Twisted has saved me hundreds or even thousands of lines of code...
Mark Bailey
------------------------------
from twisted.conch.telnet import StatefulTelnetProtocol from twisted.internet import reactor, protocol from twisted.protocols.basic import LineReceiver
class TelnetEcho(StatefulTelnetProtocol): def connectionMade(self): self.factory.connection.append(self) self.sendLine("Welcome to SimpleServer5\r\n")
def lineReceived(self, data): data = data.rstrip('\n\r')
if data.upper() == 'BYE': self.sendLine("Goodbye...\r") self.transport.loseConnection() else: self.sendLine("Unrecognized command: %r\r" % (data,))
def connectionLost(self, reason): self.factory.connection.remove(self)
class TelnetEchoFactory(protocol.Factory): protocol = TelnetEcho def __init__(self): self.connection = []
def createTelnetServer(port=7300): telnetinstance = TelnetEchoFactory() # needs to be a list reactor.listenTCP(port,telnetinstance)
if __name__ == "__main__": reactor.callWhenRunning(createTelnetServer) reactor.run()
------------------------------------------------------------------------
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAktzC0MACgkQigE4AbflYer9nwCgixra0FaTD6ubvGJufjApRG/m A34An3C2ng+4x3/halWSgGQUvQvsCiTM =Cg6W -----END PGP SIGNATURE-----
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
participants (2)
-
Arjan Scherpenisse
-
Mark Bailey