I have set up a TCP server using the twisted example (with some modifications).
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
from os import path
import yaml
class User(LineReceiver):
def __init__(self,users):
self.users = users
self.name = None
def connectionMade(self):
print 'new connection'
self.sendLine('username:')
def connectionLost(self,reason):
print 'connection lost'
if not self.name == None:
msg = '%s has disconnected' % (self.name)
print msg
self.toAll(msg,None)
del self.users[self.name]
def lineRecieved(self,line):
print line
if self.name == None:
self.setName(line)
else:
self.toChat(line)
def toAll(self,msg,to_self):
for name, protocol in self.users.iteritems():
if protocol == self and not to_self == None:
self.sendLine(to_self)
else:
protocol.sendLine(msg)
def setName(self,name):
if self.users.has_key(name):
self.sendLine('username in use')
return
elif ' ' in name:
self.sendLine('no spaces!')
return
print 'new user %s' % (name)
self.sendLine('logged in as %s' % (name))
self.name = name
self.users[name] = self
def toChat(self,message):
msg = '<%s> %s' % (self.name,message)
print msg
to_self = '<%s (you)> %s' % (self.name,message)
self.toAll(msg,to_self)
class Main(Factory):
def __init__(self,motd=None):
self.users = {}
self.motd = motd
print 'loaded, waiting for connections...'
def buildProtocol(self,addr):
return User(self.users)
if not path.isfile('config.yml'):
open('config.yml','w').write('port: 4444\nmotd: don\'t spam')
with open('config.yml','r') as f:
dump = yaml.load(f.read())
motd = dump['motd']
port = dump['port']
reactor.listenTCP(port,Main(motd=motd))
reactor.run()
I was wondering how I would be able to connect to it? I've tried adapting their example Echo client and Echo server, but my server only gives a giant error when data is sent back to it.
(The echo server is here and the echo client is here)
The client I am using is
from twisted.internet import reactor
from twisted.internet.protocol import Protocol,ClientFactory
class Main(Protocol):
def dataReceived(self,data):
print data
self.transport.write(data)
class MainFactory(ClientFactory):
def buildProtocol(self,addr):
print 'connected'
return Main()
def clientConnectionLost(self,connector,reason):
print 'connection lost'
def clientConnectionFailed(self,connector,reason):
print 'connection failed'
reactor.connectTCP('localhost',4444,MainFactory())
reactor.run()
Here is a picture of the error
What do I need to do to send data back to the server? What class do I need to inherit from?
The problem is a simple typo.
LineReceiver calls its lineReceived method on each line. You're supposed to override that. But you don't, you define lineRecieved instead. So, you get the default implementation, which raises NotImplemented.
If you fix that, your code is still more than a little odd. Trace through the communication.
The client connects, which calls the server's User.connectionMade, which does this:
self.sendLine('username:')
So the client gets that in Main.dataReceived and does this:
self.transport.write(data)
So, it's sending the prompt back as a response.
The server will receive that in lineReceived (once you fix the name) and do this:
if self.name == None:
self.setName(line)
So, you're going to set the username to 'username:'.
Related
I know a similar question has been asked here, but I am still battling with the following issue:
I am using putty as a telnet client and am using Win10. The code is given below. When I start the reactor and then connect a client, I get a response after each character is typed which is printed using the dataReceived function. However I can never seem to get the function lineReceived() to fire. I also tried a simple chat server example which worked fine using the lineReceived() function (and that example had no dataReceived() function. I tried commenting out dataReceived(), thinking perhaps it was masking out lineReceived().
In the code below, I cannot get lineReceived() to fire , only dataReceived() fires after each character is typed.
#! C:/Python37/python.exe
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from datetime import datetime, tzinfo, timedelta
from twisted.protocols.basic import LineReceiver
class Echo(Protocol):
def dataReceived(self, data):
self.transport.write(data)
class LineReceiver(Protocol):
print("Starting.......")
delimiter = "\n"
TIMEOUT = 300 # Client timeout period in seconds
def timeOut(self):
print("Client: %s. %s" % (self.addr, "Connection Timed out"))
self.transport.loseConnection()
def lineLengthExceeded(self, line):
return self.transport.loseConnection()
def connectionMade(self):
print("Connected......")
self.transport.write(b"hell...")
self.timeout = reactor.callLater(
self.TIMEOUT, self.timeOut
) # start client timeout timer
self.addr = self.transport.getPeer().host
addr = self.addr
self.addr_test = self.transport.getPeer().host
self.factory.NUM_CLIENTS += 1
def connectionLost(self, reason):
print("Lost.......")
# self.sendMsg("- %s left." % self.name)
self.transport.write(b"a client left")
self.factory.NUM_CLIENTS -= 1
print("Client disconnected: - " + str(self.addr))
print("Number of connections = %s" % self.factory.NUM_CLIENTS)
# def dataReceived(self, data): # this runs a few times after an initial connection
# self.transport.write(b"you typed: " + data +b"\n" + b"\r")
# print(data) # prints to log file with byte order marks
def lineReceived(self, line):
self.sendLine(b"Welcome, %s!" % (name,))
self.transport.write(b"line rx function...")
class DataFactory(Factory):
protocol = LineReceiver
NUM_CLIENTS = 0
def main():
print("Started...Listening for incoming connections.")
if __name__ == "__main__":
main()
reactor.listenTCP(10003, DataFactory())
reactor.run()
You overwrote LineReceiver with your own Protocol subclass, which does not have a lineReceived() method. You just gave me a good reason for using the module path as a namespace instead of importing a specific object :D
from twisted.protocols import basic
from twisted.internet import endpoints, protocol, reactor
class LnRcv(basic.LineReceiver):
def lineReceived(self, line):
print(line)
class DataFactory(protocol.Factory):
protocol = LnRcv
server = endpoints.TCP4ServerEndpoint(reactor, 10003)
server.listen(DataFactory())
reactor.run()
Update
I had some spare time to fix your code. You have string/bytes mismatching all over and unreferenced objects that were not in your original code. Here's an example that should work and give you a base to off of.
from uuid import uuid4
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet.protocol import Factory, Protocol
from twisted.protocols.basic import LineReceiver
class LnRcv(LineReceiver):
# Client timeout period in seconds
TIMEOUT = 10
def timeOut(self):
print ("Client: %s. %s" % (self.addr, 'Connection Timed out' ))
self.transport.loseConnection()
def connectionMade(self):
self.factory.NUM_CLIENTS += 1
print(f"Connected......number of connections = {self.factory.NUM_CLIENTS}")
peer = self.transport.getPeer()
self.addr = f"{peer.host}:{peer.port}"
self.name = uuid4().hex[:9].upper()
self.transport.write(f"Hello! I temporarily set your ID to {self.name}. What is your name? ".encode("utf8"))
# Start client timeout timer
self.timeout = reactor.callLater(self.TIMEOUT, self.timeOut)
def connectionLost(self, reason):
self.factory.NUM_CLIENTS -= 1
print(f"- {self.name} left because:\n{reason.getErrorMessage()}")
print(f"- Client disconnected: - {self.addr}")
print(f"- Number of connections = {self.factory.NUM_CLIENTS}")
def lineReceived(self, line):
self.sendLine(f"Welcome, {line.decode('utf8')}!".encode("utf8"))
class DataFactory(Factory):
protocol = LnRcv
NUM_CLIENTS = 0
def main():
print("Started...Listening for incoming connections.")
server = TCP4ServerEndpoint(reactor, 10003)
server.listen(DataFactory())
reactor.run()
if __name__ == "__main__":
main()
I am new to the Twisted framework for python. I am playing around with a customer DNS server and I want to know how to located the SRC_IP of the DNS Request.
I am using the following script: http://twisted.readthedocs.org/en/latest/names/howto/custom-server.html
Specifically the one that dynamically resolves and want to know how I can located the source IP of the Request.
Thanks
Not being overly familiar with twisted, I don't know if this is the best way. I suspect that what I propose below is not because operating directly on the sockets doesn't feel right, but here it goes.
Subclass server.DNSServerFactory and override the handleQuery() method, for example:
import socket
from twisted.internet.address import IPv4Address
class MyDNSServerFactory(server.DNSServerFactory):
def handleQuery(self, message, protocol, address):
if protocol.transport.socket.type == socket.SOCK_STREAM:
self.peer_address = protocol.transport.getPeer()
elif protocol.transport.socket.type == socket.SOCK_DGRAM:
self.peer_address = IPv4Address('UDP', *address)
else:
print "Unexpected socket type %r" % protocol.transport.socket.type
print "Got message from : %r" % self.peer_address
return server.DNSServerFactory.handleQuery(self, message, protocol, address)
.
.
.
factory = MyDNSServerFactory(
clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
)
Things to worry about:
IPV6 addresses
Direct use of socket seems underhanded.
Does socket.SOCK_STREAM always imply a TCP connection?
There are other ways to do it, e.g. subclass dns.DNSDatagramProtocol and override datagramReceived(self, data, addr) to get the client UDP address. TCP client addresses would be gotten by subclassing and overriding server.DNSServerFactory.connectionMade(self, protocol) and getting the peer's address with protocol.transport.getPeer().
Updated answer to make peer address available in DynamicResolver
Modify MyDNSServerFactory.handleQuery() to set peer_address for resolvers that have a peer_address attribute:
class MyDNSServerFactory(server.DNSServerFactory):
def handleQuery(self, message, protocol, address):
if protocol.transport.socket.type == socket.SOCK_STREAM:
self.peer_address = protocol.transport.getPeer()
elif protocol.transport.socket.type == socket.SOCK_DGRAM:
self.peer_address = IPv4Address('UDP', *address)
else:
print "Unexpected socket type %r" % protocol.transport.socket.type
print "Got message from : %r" % self.peer_address
# Make peer_address available to resolvers that support that attribute
for resolver in self.resolver.resolvers:
if hasattr(resolver, 'peer_address'):
resolver.peer_address = self.peer_address
return server.DNSServerFactory.handleQuery(self, message, protocol, address)
Add the following peer_address property to class DynamicResolver:
def __init__(self):
self._peer_address = None
#property
def peer_address(self):
return self._peer_address
#peer_address.setter
def peer_address(self, value):
self._peer_address = value
Now you can access peer_address in DynamicResolver.query(), e.g.
def query(self, query, timeout=None):
print "In DynamicResolver.query(): self.peer_address = %r" % self.peer_address
if self._dynamicResponseRequired(query):
return defer.succeed(self._doDynamicResponse(query))
else:
return defer.fail(error.DomainError())
I'm writing an asyncore server which fetches info from another module in same process and writes it back to client. The info basically is a dictionary where for each key we have a queue of messages. I'm required to dump the length of each queue. The code runs fine on a test machine but as soon as I install it on a production server I start getting following error message : "socket.error'>:[Errno 32] Broken pipe)".
This is the server:
class request_handler (asyncore.dispatcher):
def __init__(self, conn_sock, client_address, dict):
self.client_address = client_address
self.buffer = ""
self.dict = dict
asyncore.dispatcher.__init__(self, conn_sock)
def readable(self):
return True
def writable(self):
return False
def handle_read(self):
data = self.recv(SIZE)
mtats = "msgq-stats"
if data:
buffer = data
if buffer.lower() == mstats.lower():
msgout = "-- Message Queue Stats --\n"
for key, value in dict.items():
mq = 0
if dict[key].message_queue:
mq = len(dict[key].message_queue)
msgout += key + ":" + str(mq) + "\n"
self.send(msgout)
else: self.send("Invalid input\n")
else:
self.send("Invalid input\n")
def handle_write(self):
print ("--Handling read--\n")
def handle_close(self):
pass
# ---------------------------------------------------------------------
class monitor_server (asyncore.dispatcher):
def __init__ (self, ip, port, destination):
sys.path.append('/path/')
import dict
self.ip = ip
self.port = port
self.dict = dict
asyncore.dispatcher.__init__ (self)
self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind ((ip, port))
self.listen (5)
def writable (self):
return 0
def handle_read (self):
pass
def readable (self):
return self.accepting
def handle_connect (self):
pass
def handle_accept (self):
(conn_sock, client_address) = self.accept()
request_handler (conn_sock, client_address, self.destination)
and this is the client code:
class Client(asyncore.dispatcher_with_send):
def __init__(self, host, port, message):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, port))
print "Message being sent is "
print message
self.out_buffer = message
def handle_close(self):
self.close()
def handle_read(self):
print self.recv(1024)
self.close()
c = Client('', 6000, 'msgq-stats')
asyncore.loop()
Thanks in advance.
That's an error case you have to handle. Sometimes connections will close. It's normal for different socket errors to be encountered during development as compared to in production, since there are so many different possible errors and they almost entirely depend on the execution environment and what the program on the other side of the connection is doing and on what all the routers between the client and the server decide to do.
So, the literal answer to your question is that you need to handle this and many other socket errors in your application code. That's part of your job when you use asyncore. Add the necessary exception handling and mark the connection as closed when something like this happens.
A slightly better answer is that there are higher level tools that make network programming easier, and you should probably consider using those. The big thing in this area is Twisted.
I've got a problem with setting up a client which connects to a "distributor" server to send certain data.
The server's purpose is to get data from the client and then send that data to it's all connected clients. The server works without any issues.
The main client is also supposed to work as an IRC bot.
Here's a text example of how it should work like:
(IRC) John: Hello there!
1. The IRC client got the message, we need to send it to the distributor now.
2. Distributor should get this "John: Hello there!" string and send it back to it's all connected clients.
3. If other clients send data to the distributor, which this will broadcast to all clients, the IRC client should output at it's turn the received data to a specified channel
The following code is the IRC bot client (ircbot.py):
import sys
import socket
import time
import traceback
from twisted.words.protocols import irc
from twisted.internet import reactor
from twisted.internet import protocol
VERBOSE = True
f = None
class IRCBot(irc.IRCClient):
def _get_nickname(self):
return self.factory.nickname
nickname = property(_get_nickname)
def signedOn(self):
self.msg("NickServ", "id <password_removed>") # Identify the bot
time.sleep(0.1) # Wait a little...
self.join(self.factory.channel) # Join channel #chantest
print "Signed on as %s." % (self.nickname,)
def joined(self, channel):
print "Joined %s." % (channel,)
def privmsg(self, user, channel, msg):
name = user.split('!', 1)[0]
prefix = "%s: %s" % (name, msg)
print prefix
if not user:
return
if self.nickname in msg:
msg = re.compile(self.nickname + "[:,]* ?", re.I).sub('', msg)
print msg
else:
prefix = ''
if msg.startswith("!"):
if name.lower() == "longdouble":
self.msg(channel, "Owner command") # etc just testing stuff
else:
self.msg(channel, "Command")
if channel == "#testchan" and name != "BotName":
EchoClient().sendData('IRC:'+' '.join(map(str, [name, msg])))
# This should make the bot send chat data to the distributor server (NOT IRC server)
def irc_NICK(self, prefix, params):
"""Called when an IRC user changes their nickname."""
old_nick = prefix.split('!')[0]
new_nick = params[0]
self.msg(, "%s is now known as %s" % (old_nick, new_nick))
def alterCollidedNick(self, nickname):
return nickname + '1'
class BotFactory(protocol.ClientFactory):
protocol = IRCBot
def __init__(self, channel, nickname='BotName'):
self.channel = channel
self.nickname = nickname
def clientConnectionLost(self, connector, reason):
print "Lost connection (%s), reconnecting." % (reason,)
connector.connect()
def clientConnectionFailed(self, connector, reason):
print "Could not connect: %s" % (reason,)
class EchoClient(protocol.Protocol):
def connectionMade(self):
pass
def sendData(self, data):
self.transport.write(data)
def dataReceived(self, data):
if VERBOSE:
print "RECV:", data
IRC.msg("#chantest", data)
#This one should send the received data from the distributor to the IRC channel
def connectionLost(self, reason):
print "Connection was lost."
class EchoFactory(protocol.ClientFactory):
def startedConnecting(self, connector):
print 'Started to connect.'
def buildProtocol(self, addr):
print 'Connected to the Distributor'
return EchoClient()
def clientConnectionFailed(self, connector, reason):
print "Cannot connect to distributor! Check all settings!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Distributor Lost connection!!"
reactor.stop()
if __name__ == "__main__":
IRC = BotFactory('#chantest')
reactor.connectTCP('irc.rizon.net', 6667, IRC) # Our IRC connection
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f) # Connection to the Distributor server
reactor.run()
The following code is the distributor server (distributor.py):
(This one works fine, but maybe it could be useful for further reference)
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class MultiEcho(Protocol):
def __init__(self, factory):
self.factory = factory
def connectionMade(self):
print "Client connected:",self
self.factory.echoers.append(self)
self.factory.clients = self.factory.clients+1
#self.transport.write("Welcome to the server! There are currently "+`self.factory.clients`+" clients connected.")
def dataReceived(self, data):
print "RECV:",data
for echoer in self.factory.echoers:
echoer.transport.write(data)
def connectionLost(self, reason):
print "Client disconnected:",self
self.factory.echoers.remove(self)
self.factory.clients = self.factory.clients-1
class MultiEchoFactory(Factory):
def __init__(self):
self.clients = 0
self.names = []
self.echoers = []
def buildProtocol(self, addr):
return MultiEcho(self)
if __name__ == '__main__':
print "Running..."
reactor.listenTCP(8000, MultiEchoFactory())
reactor.run()
I want the client to output all incoming chat data from the IRC server to the "distributor" server and also output incoming data from the "distributor".
However, I get errors like this:
For the following line in ircbot.py,
EchoClient().sendData('IRC'+' '.join(map(str, [name, msg])))
I get the following error:
Joined #chantest.
Longdouble: test
Traceback (most recent call last):
File "C:\Python\lib\site-packages\twisted\internet\tcp.py", line 460, in doRea
d
return self.protocol.dataReceived(data)
File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 2277,
in dataReceived
basic.LineReceiver.dataReceived(self, data.replace('\r', ''))
File "C:\Python\lib\site-packages\twisted\protocols\basic.py", line 564, in da
taReceived
why = self.lineReceived(line)
File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 2285,
in lineReceived
self.handleCommand(command, prefix, params)
--- <exception caught here> ---
File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 2329,
in handleCommand
method(prefix, params)
File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 1813,
in irc_PRIVMSG
self.privmsg(user, channel, message)
File "C:\Python\Traance\kwlbot\ircbot.py", line 51, in privmsg
EchoClient().sendData('IRC'+' '.join(map(str, [name, msg])))
File "C:\Python\Traance\kwlbot\ircbot.py", line 90, in sendData
self.transport.write(data)
exceptions.AttributeError: 'NoneType' object has no attribute 'write'
And same goes to this line in the same ircbot.py
IRC.msg("#chantest", data)
->
RECV: Hello from Distributor Server
Traceback (most recent call last):
File "C:\Python\Traance\kwlbot\ircbot.py", line 96, in dataReceived
IRC.msg("#chantest", data)
AttributeError: BotFactory instance has no attribute 'msg'
What am I doing wrong? How can I call the right function from the IRCbot class to make it send the data to the distributor server and data received from the distributor server to output in the specified channel via IRC?
Any suggestions and possible solutions are welcome.
If I missed any other details, please let me know.
Thank you for your time!
You should avoid writing blocking code like this:
def signedOn(self):
self.msg("NickServ", "id <password_removed>") # Identify the bot
time.sleep(0.1) # Wait a little...
self.join(self.factory.channel) # Join channel #chantest
print "Signed on as %s." % (self.nickname,)
For details, see Tail -f log on server, process data, then serve to client via twisted.
Apart from that, the main problem here is that you are trying to send data without having a connection. When you write something like:
EchoClient().sendData('IRC'+' '.join(map(str, [name, msg])))
you're creating a protocol instance which is responsible for handling a connection and then trying to use it, but you're not creating a connection. The attempt to send data fails because the protocol hasn't been attached to any transport.
Your snippet already demonstrates the correct way to create a connection, twice in fact:
IRC = BotFactory('#chantest')
reactor.connectTCP('irc.rizon.net', 6667, IRC) # Our IRC connection
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f) # Connection to the Distributor server
The mistake is creating a new EchoClient instance, one with no connection. The reactor.connectTCP call creates a new connection and a new EchoClient instance and associates them with each other.
Instead of EchoClient().sendData(...), you want to use the EchoClient instance created by your factory:
def buildProtocol(self, addr):
print 'Connected to the Distributor'
return EchoClient()
Your buildProtocol implementation creates the instance, all that's missing is for it to save the instance so it can be used by your IRC bot.
Consider something like this:
def buildProtocol(self, addr):
print 'Connected to the Distributor'
self.connection = EchoClient()
return self.connection
Your IRC client can then use the saved EchoClient instance:
if channel == "#testchan" and name != "BotName":
f.connection.sendData('IRC:'+' '.join(map(str, [name, msg])))
# This should make the bot send chat data to the distributor server (NOT IRC server)
Note that the specific code I give here is a very crude approach. It uses the global variable f to find the EchoFactory instance. As with most global variable usage this makes the code a little hard to follow. Further, I haven't added any code to handle connectionLost events to clear the connection attribute out. This means you might think you're sending data to the distributed server when the connection has already been lost. And similarly, there's no guarantee that the connection to the distributed server will have been created by the time the IRC client first tries to use it, so you may have an AttributeError when it tries to use f.connection.sendData.
However, fixing these doesn't require much of a leap. Fix the global variable usage as you would any other - by passing arguments to functions, saving objects as references on other objects, etc. Fix the possible AttributeError by handling it, or by not creating the IRC connection until after you've created the distributed connection, etc. And handle lost connections by resetting the attribute value to None or some other sentinel, and paying attention to such a case in the IRC code before trying to use the distributed client connection to send any data.
TFM is never defined in your code, so I don't know what the deal is there.
The other error is that you're instantiating a client, but never connecting it to anything, as with reactor.connectTCP(...) or endpoint.connect(...). The transport attribute will be None until it's set by something.
(It would be helpful for you to come up with a simpler version of this code which is complete and doesn't include unnecessary details like all the printed log messages. It makes it harder to see what the real issues are.)
One of my protocols is connected to a server, and with the output of that I'd like to send it to the other protocol.
I need to access the 'msg' method in ClassA from ClassB but I keep getting: exceptions.AttributeError: 'NoneType' object has no attribute 'write'
Actual code:
from twisted.words.protocols import irc
from twisted.internet import protocol
from twisted.internet.protocol import Protocol, ClientFactory
from twisted.internet import reactor
IRC_USERNAME = 'xxx'
IRC_CHANNEL = '#xxx'
T_USERNAME = 'xxx'
T_PASSWORD = md5.new('xxx').hexdigest()
class ircBot(irc.IRCClient):
def _get_nickname(self):
return self.factory.nickname
nickname = property(_get_nickname)
def signedOn(self):
self.join(self.factory.channel)
print "Signed on as %s." % (self.nickname,)
def joined(self, channel):
print "Joined %s." % (channel,)
def privmsg(self, user, channel, msg):
if not user:
return
who = "%s: " % (user.split('!', 1)[0], )
print "%s %s" % (who, msg)
class ircBotFactory(protocol.ClientFactory):
protocol = ircBot
def __init__(self, channel, nickname=IRC_USERNAME):
self.channel = channel
self.nickname = nickname
def clientConnectionLost(self, connector, reason):
print "Lost connection (%s), reconnecting." % (reason,)
connector.connect()
def clientConnectionFailed(self, connector, reason):
print "Could not connect: %s" % (reason,)
class SomeTClass(Protocol):
def dataReceived(self, data):
if data.startswith('SAY'):
data = data.split(';', 1)
# RAGE
#return self.ircClient.msg(IRC_CHANNEL, 'test')
def connectionMade(self):
self.transport.write("mlogin %s %s\n" % (T_USERNAME, T_PASSWORD))
class tClientFactory(ClientFactory):
def startedConnecting(self, connector):
print 'Started to connect.'
def buildProtocol(self, addr):
print 'Connected.'
return t()
def clientConnectionLost(self, connector, reason):
print 'Lost connection. Reason:', reason
def clientConnectionFailed(self, connector, reason):
print 'Connection failed. Reason:', reason
if __name__ == "__main__":
#chan = sys.argv[1]
reactor.connectTCP('xxx', 6667, ircBotFactory(IRC_CHANNEL) )
reactor.connectTCP('xxx', 20184, tClientFactory() )
reactor.run()
Any ideas please? :-)
Twisted FAQ:
How do I make input on one connection
result in output on another?
This seems like it's a Twisted
question, but actually it's a Python
question. Each Protocol object
represents one connection; you can
call its transport.write to write some
data to it. These are regular Python
objects; you can put them into lists,
dictionaries, or whatever other data
structure is appropriate to your
application.
As a simple example, add a list to
your factory, and in your protocol's
connectionMade and connectionLost, add
it to and remove it from that list.
Here's the Python code:
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class MultiEcho(Protocol):
def connectionMade(self):
self.factory.echoers.append(self)
def dataReceived(self, data):
for echoer in self.factory.echoers:
echoer.transport.write(data)
def connectionLost(self, reason):
self.factory.echoers.remove(self)
class MultiEchoFactory(Factory):
protocol = MultiEcho
def __init__(self):
self.echoers = []
reactor.listenTCP(4321, MultiEchoFactory())
reactor.run()