[Twisted-Python] How to dispatch message to different servers
Hi, I have to replace a piece of software that sniffs the traffic on one interface. It gets different messages that are each associated to a specific emitter. On the same machine, one server is started for each emitter (on a different port). And the application is just supposed to use the proper server to send the messages captured (to a client on another machine). Not sure if it's clear, but basically if I have 2 emitters A and B, I'll start 2 servers (a and b). My sniffer will get messages A1, A2, B1, B2, B3... I have to pass messages A1, A2 to server a, that will just send them to the client (if it is connected of course). And B1, B2, B3 to server b. I don't need any buffering. If no client is connected, messages captured are just discarded. To sniff the network, I want to use pylibpcap or pcapy. I found this example to make it work with twisted: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet... Starting several servers that use the same protocol is not a problem. But how do I pass the messages captured to the right server? How do I make the link between the function sniffing the network and the servers? Thanks Benjamin
Well, you'd presumably have a connection to each of the servers in the form of a client factory and a protocol instance. Then, every time you get a message, you figure out which protocol instance you want (the one for the appropriate server) and send a message to it. You could do that with self.transport.write, of course, but it would be much easier to just use a ready-made RPC thing. One such RPC thing is AMP, which comes with Twisted. You can read more about it here: http://amp-protocol.net/ https://twistedmatrix.com/documents/current/core/howto/amp.html You will probably end up having a command like HandlePacket or something (presumably you can come up with a more apt domain-specific name), and something close to self.servers[serverFor(packet.origin)].callRemote(HandlePacket, packet.data), or whatever. I realize this is still pretty vague and high level, so feel free to ask more questions about the parts that are unclear :) On Thu, Feb 28, 2013 at 10:59 PM, Benjamin BERTRAND <beenje@gmail.com>wrote:
Hi,
I have to replace a piece of software that sniffs the traffic on one interface. It gets different messages that are each associated to a specific emitter. On the same machine, one server is started for each emitter (on a different port). And the application is just supposed to use the proper server to send the messages captured (to a client on another machine).
Not sure if it's clear, but basically if I have 2 emitters A and B, I'll start 2 servers (a and b). My sniffer will get messages A1, A2, B1, B2, B3... I have to pass messages A1, A2 to server a, that will just send them to the client (if it is connected of course). And B1, B2, B3 to server b. I don't need any buffering. If no client is connected, messages captured are just discarded.
To sniff the network, I want to use pylibpcap or pcapy. I found this example to make it work with twisted: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet...
Starting several servers that use the same protocol is not a problem. But how do I pass the messages captured to the right server? How do I make the link between the function sniffing the network and the servers?
Thanks
Benjamin _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh
Thanks for the answer! I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-) I guess I can use the same factory to start all my servers. So I start my sniffer (in a thread) in my ServerFactory and I keep a dictionary of deferred for each line (corresponds to an emitter and a server port). It allows me to call the messageToSend method corresponding to the proper server when receiving data. Here is a code extract of what I implemented: class Oldimon(Protocol): def __init__(self, factory): self.factory = factory self.line = None def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend) class OldimonFactory(ServerFactory): def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT))) def buildProtocol(self, addr): return Oldimon(self) def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data) oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run() Le 1 mars 2013 à 15:31, Laurens Van Houtven <_@lvh.cc> a écrit :
Well, you'd presumably have a connection to each of the servers in the form of a client factory and a protocol instance. Then, every time you get a message, you figure out which protocol instance you want (the one for the appropriate server) and send a message to it. You could do that with self.transport.write, of course, but it would be much easier to just use a ready-made RPC thing.
One such RPC thing is AMP, which comes with Twisted. You can read more about it here:
http://amp-protocol.net/ https://twistedmatrix.com/documents/current/core/howto/amp.html
You will probably end up having a command like HandlePacket or something (presumably you can come up with a more apt domain-specific name), and something close to self.servers[serverFor(packet.origin)].callRemote(HandlePacket, packet.data), or whatever.
I realize this is still pretty vague and high level, so feel free to ask more questions about the parts that are unclear :)
On Thu, Feb 28, 2013 at 10:59 PM, Benjamin BERTRAND <beenje@gmail.com> wrote: Hi,
I have to replace a piece of software that sniffs the traffic on one interface. It gets different messages that are each associated to a specific emitter. On the same machine, one server is started for each emitter (on a different port). And the application is just supposed to use the proper server to send the messages captured (to a client on another machine).
Not sure if it's clear, but basically if I have 2 emitters A and B, I'll start 2 servers (a and b). My sniffer will get messages A1, A2, B1, B2, B3... I have to pass messages A1, A2 to server a, that will just send them to the client (if it is connected of course). And B1, B2, B3 to server b. I don't need any buffering. If no client is connected, messages captured are just discarded.
To sniff the network, I want to use pylibpcap or pcapy. I found this example to make it work with twisted: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet...
Starting several servers that use the same protocol is not a problem. But how do I pass the messages captured to the right server? How do I make the link between the function sniffing the network and the servers?
Thanks
Benjamin _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
On Mar 1, 2013, at 1:52 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
In what way is it "overkill"? The dictionary says that <http://dictionary.reference.com/browse/overkill> is "an excess of what is required or suitable, as because of zeal or misjudgment". What is AMP too much of? Memory? CPU? Bandwidth? API complexity? Code size? As compared to what? -glyph
Le 1 mars 2013 à 23:27, Glyph <glyph@twistedmatrix.com> a écrit :
On Mar 1, 2013, at 1:52 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
In what way is it "overkill"? The dictionary says that <http://dictionary.reference.com/browse/overkill> is "an excess of what is required or suitable, as because of zeal or misjudgment". What is AMP too much of? Memory? CPU? Bandwidth? API complexity? Code size? As compared to what?
"overkill" wasn't maybe the proper term to use. I was just referring to code complexity based on my knowledge, or lack of knowledge :-) I had the impression AMP is used when you need to exchange various command/response. I don't need all that "power" as I just want to pass some messages. I thought using a deferred like I did in my code example was easier. Not sure though as Jean-Paul pointed it probably doesn't work. My server already uses a specific protocol to communicate with the client. So I don't really see how to integrate AMP there. Do you have any example? Thanks Benjamin
-glyph _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
On 03/01/2013 10:27 PM, Glyph wrote:
What is AMP too much of? Memory? CPU? Bandwidth? API complexity? Code size? As compared to what?
FWIW, every time (all three of them...) I've looked at AMP I got rapidly bored and ended up using PB. My use-cases have usually been Twisted->Twisted, and the AMP "Command" definition, and syncing said defs up at both ends, was hassle I didn't need. When I need to talk to external systems I almost always use some REST, XMLRPC or JSON-RPC interface, because they're usually available out-of-the-box. I also don't care for the idea of statically typing the command defs; I'm sure this helps when talking to languages with crappy typing systems, but honestly - who uses Java these days? ;o)
Fair enough, I only use AMP as the external interface (e.g. Javascript talking to me from a browser). On Sat, Mar 2, 2013 at 12:25 PM, Phil Mayers <p.mayers@imperial.ac.uk>wrote:
On 03/01/2013 10:27 PM, Glyph wrote:
What is AMP too much of? Memory? CPU? Bandwidth? API complexity? Code size? As compared to what?
FWIW, every time (all three of them...) I've looked at AMP I got rapidly bored and ended up using PB. My use-cases have usually been Twisted->Twisted, and the AMP "Command" definition, and syncing said defs up at both ends, was hassle I didn't need.
When I need to talk to external systems I almost always use some REST, XMLRPC or JSON-RPC interface, because they're usually available out-of-the-box.
I also don't care for the idea of statically typing the command defs; I'm sure this helps when talking to languages with crappy typing systems, but honestly - who uses Java these days? ;o)
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh
On Mar 2, 2013, at 3:25 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 03/01/2013 10:27 PM, Glyph wrote:
What is AMP too much of? Memory? CPU? Bandwidth? API complexity? Code size? As compared to what?
FWIW, every time (all three of them...) I've looked at AMP I got rapidly bored and ended up using PB. My use-cases have usually been Twisted->Twisted, and the AMP "Command" definition, and syncing said defs up at both ends, was hassle I didn't need.
When I need to talk to external systems I almost always use some REST, XMLRPC or JSON-RPC interface, because they're usually available out-of-the-box.
I also don't care for the idea of statically typing the command defs; I'm sure this helps when talking to languages with crappy typing systems, but honestly - who uses Java these days? ;o)
I wrote a blog post some time ago explaining why you want static declarations, even if your programming language is all nice and dynamic: <http://glyph.twistedmatrix.com/2008/07/static-on-wire.html> Even if all you care about is Twisted->Twisted, there are potential resource exhaustion and implementation-confusion attacks against PB that are very hard to mitigate in its current form. That said, for the sorts of places where PB is useful (communicating about and synchronizing arbitrarily deep and complex object graphs), you're probably going to have those exhaustion attacks anyway and using something like AMP would just be more typing. So as long as you're version-synchronized and at least partially trusted on both ends of the wire, PB is a fine choice as well. "REST" (by which you mean "HTTP", I'm sure), XMLRPC, and JSON-RPC are not full replacements for AMP because they're asymmetrical and don't support pipelining. With AMP, a client can receive requests from a server, you don't need to have a TCP handshake for every request, you can receive responses out of order, and you can receive a request while waiting for a response, and so on. -glyph
On 03/02/2013 12:19 PM, Glyph wrote:
I wrote a blog post some time ago explaining why you want static declarations, even if your programming language is all nice and dynamic:
Being able to "early drop" bad PDUs is a fine notion, but it's not a property that comes with zero cost. If you feel that the cost/benefit tradeoff is not useful in your case (and I do) then it doesn't make sense to pay it. AMP would be somewhat more attractive (to me) if it were possible to run with the IDL just on the "server" (i.e. callee); this would achieve the goal of protocol-level sanity checking, without the cost of having to distribute the IDL to the clients. Presumably it would be possible to implement this now - have an AMP discovery command that dynamically builds the client-side IDLs. But there's no incentive for me to do that. For the use-cases I have, the protocol version/interop problem is not relevant.
not full replacements for AMP because they're asymmetrical and don't support pipelining. With AMP, a client can receive requests from a server, you don't need to have a TCP handshake for every request, you
You don't need to do a TCP handshake for every request in any of those protocols either. Long-lived TCP/HTTP sessions are quite common, though not universal. It will be interesting to see if and how HTTP/2.0 solves a lot of these issues.
can receive responses out of order, and you can receive a request while waiting for a response, and so on.
Obviously. But I would tend to use those protocols when either those properties are not needed (perhaps even undesireable) and may be impossible to make use of (if the far end is a synchronous, blocking client unable to make use of out-of-order responses or server-initiated messages). In those cases, it would also be rare for AMP to be available, and it certainly wouldn't be pre-installed. "Install this Java library on your Oracle servers then..." "Ha ha no go away." You seemed curious why someone wouldn't use AMP. Personally I have two common use-cases: 1. Communicating between two trusted Twisted processes, for which PB is good enough. 2. Communicating with a semi-trusted third party process, for which a RESTful interface or XML/JSON RPCs are *available* and sufficiently secure and capable for my needs. Obviously other people will have radically different needs, but for me, AMP adds little. Cheers, Phil
On Sat, Mar 2, 2013 at 3:46 PM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
AMP would be somewhat more attractive (to me) if it were possible to run with the IDL just on the "server" (i.e. callee); this would achieve the goal of protocol-level sanity checking, without the cost of having to distribute the IDL to the clients. Presumably it would be possible to implement this now - have an AMP discovery command that dynamically builds the client-side IDLs. But there's no incentive for me to do that.
I don't really understand how this is any easier with PB than with AMP, though. With AMP, you "just" need the same command definitions on both sides. With PB, you need the exact same Python code versions for every class you are sending over the wire; if achieving this is not a problem, then why is it problematic to get the same AMP command definitions on both sides?
You don't need to do a TCP handshake for every request in any of those protocols either. Long-lived TCP/HTTP sessions are quite common, though not universal.
You don't quite have to do a TCP handshake for every request you want to send over an HTTP channel, but there are still some problems. Connection keep-alive means you can send another request after you have received a response, without reconnecting; pipelining means you can send another request right away, but you still won't get the response until after you receive the first response. In addition, there are various error handling situations where you are basically forced to close the connection and open a new one. By contrast, an AMP connection can have any number of AMP request/response exchanges in flight at one time, in either direction; the closest thing to this in HTTP-land is SPDY's connection multiplexing, but that's still asymmetric (client makes requests to the server, server cannot make requests to the client, so you need to do some kind of long polling / inversion of control to simulate this). -- mithrandi, i Ainil en-Balandor, a faer Ambar
On 03/02/2013 03:24 PM, Tristan Seligmann wrote:
I don't really understand how this is any easier with PB than with AMP, though. With AMP, you "just" need the same command definitions on both sides. With PB, you need the exact same Python code versions for every class you are sending over the wire;
I don't use PB like that. I only ever send simple data structures made of builtin types (int, str, list, dict).
You don't quite have to do a TCP handshake for every request you want to send over an HTTP channel, but there are still some problems.
You're not telling me anything I don't already know. My point is that, for the use-cases *I* have, those limitations have not proven to be a problem, so the effort
asymmetric (client makes requests to the server, server cannot make requests to the client, so you need to do some kind of long polling / inversion of control to simulate this).
Yes.
On Sat, Mar 2, 2013 at 6:36 PM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
On 03/02/2013 03:24 PM, Tristan Seligmann wrote:
I don't really understand how this is any easier with PB than with AMP, though. With AMP, you "just" need the same command definitions on both sides. With PB, you need the exact same Python code versions for every class you are sending over the wire;
I don't use PB like that. I only ever send simple data structures made of builtin types (int, str, list, dict).
Interesting; I guess that's obvious in retrospect but I hadn't thought of using PB like that, and I suppose it's not possible to use AMP like that.
You don't quite have to do a TCP handshake for every request you want to send over an HTTP channel, but there are still some problems.
You're not telling me anything I don't already know.
My point is that, for the use-cases *I* have, those limitations have not proven to be a problem, so the effort of deploying a protocol which avoids those limitations is not warranted.
Sure, I didn't mean to imply otherwise, just wanted to clarify for the purposes of the discussion. It sounds like your analysis is sound for the use cases you're concerned with, I don't have any objection to that. -- mithrandi, i Ainil en-Balandor, a faer Ambar
On Mar 2, 2013, at 5:46 AM, Phil Mayers <p.mayers@imperial.ac.uk> wrote:
You seemed curious why someone wouldn't use AMP. Personally I have two common use-cases:
1. Communicating between two trusted Twisted processes, for which PB is good enough.
There are two reasons that someone might want to consider AMP in this case. I am not necessarily saying you would want to consider AMP here - you seem to be pretty happy with your decision and I'm not saying it's wrong. I even gave some reasons why PB would be a better idea sometimes. One is that it makes it a bit easier to replace one end of the wire with something that isn't Twisted - or at least, preserve the plausible deniability that you might, which can make it more politically palatable to deploy Twisted in the first place :). Granted, "use PyPy" is increasingly a better argument for the sorts of people who would want this assurance - performance nuts - than "you could re-implement in another language later". Still, if there are other reasons, or you are in an environment where another language is popular, while PB implementations for other languages do exist, and I have deployed polyglot PB clusters, it adds a surprising dimension of additional complexity. Deploying a polyglot AMP system is a breeze, even if you have to implement AMP from scratch for the other language in order to do it ;). Another reason is that it makes versioning the protocol easier. With PB, it's very easy to build a protocol that mirrors your application's internal state, and expose implementation details accidentally, which then have to be painstakingly emulated when you roll out a new version. This isn't much of a concern if your protocol is pretty stable, and/or your application upgrades are synchronized. Like you said though: writing up all those message format declarations is not zero-cost. It's certainly much quicker to get a basic PB cluster up and running since you can just toss a couple of remote_ declarations in and be off to the races. There is a good reason Twisted still ships both and we have no plans to ever get rid of PB :).
2. Communicating with a semi-trusted third party process, for which a RESTful interface or XML/JSON RPCs are *available* and sufficiently secure and capable for my needs.
For this one, obviously, XML or JSON-RPC is the right choice. I mean, heck, 90% of Twisted is implementations of messy, arguably bad protocols (IMAP? POP? **FTP?**) which you probably shouldn't use, except you have to because you want to talk to a system that uses them :).
Obviously other people will have radically different needs, but for me, AMP adds little.
Sure. It might not be for everybody. -glyph
Hey Glyph, As usual, I agree with most of what you have to say, but... On Sat, Mar 2, 2013 at 8:58 PM, Glyph <glyph@twistedmatrix.com> wrote:
Deploying a polyglot AMP system is a breeze, even if you have to implement AMP from scratch for the other language in order to do it ;).
Could you help me write an AMP implementation in Javascript? It's easy, right? ;-)
-glyph
-- cheers lvh
On Mar 2, 2013, at 12:34 PM, Laurens Van Houtven <_@lvh.cc> wrote:
Hey Glyph,
As usual, I agree with most of what you have to say, but...
On Sat, Mar 2, 2013 at 8:58 PM, Glyph <glyph@twistedmatrix.com> wrote: Deploying a polyglot AMP system is a breeze, even if you have to implement AMP from scratch for the other language in order to do it ;).
Could you help me write an AMP implementation in Javascript? It's easy, right? ;-)
No, not me. But somebody can: <https://github.com/cyli/node-amp>. -glyph
On Sat, Mar 2, 2013 at 10:34 PM, Laurens Van Houtven <_@lvh.cc> wrote:
Could you help me write an AMP implementation in Javascript? It's easy, right? ;-)
It can't be harder than writing a PB implementation in JavaScript ;) -- mithrandi, i Ainil en-Balandor, a faer Ambar
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`). Jean-Paul
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something? /Benjamin def run_pcap(device, pcap_filter, callback): def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id) p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet) class Oldimon(Protocol): def __init__(self, factory): self.factory = factory self.line = None def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend) class OldimonFactory(ServerFactory): def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT))) def buildProtocol(self, addr): return Oldimon(self) def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data) oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Yes, that looks okay, but that wasn't in your original sample ;-) I'm on my phone at the moment which isn't great for code review, but it looks like you only fire one deferred per line? On Mar 2, 2013 9:50 AM, "Benjamin BERTRAND" <beenje@gmail.com> wrote:
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something?
/Benjamin
def run_pcap(device, pcap_filter, callback):
def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id)
p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet)
class Oldimon(Protocol):
def __init__(self, factory): self.factory = factory self.line = None
def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
class OldimonFactory(ServerFactory):
def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT)))
def buildProtocol(self, addr): return Oldimon(self)
def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data)
oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Le 2 mars 2013 à 10:08, Laurens Van Houtven <_@lvh.cc> a écrit :
Yes, that looks okay, but that wasn't in your original sample ;-)
Yep, sorry about that. I was more focused on the ServerFactory and Protocol. The pcap in a thread comes from the link I mentioned in my first post: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet... But I know, it's better to put everything in one post. People shouldn't have to click links.
I'm on my phone at the moment which isn't great for code review, but it looks like you only fire one deferred per line?
There is a specific deferred by line. I re-arm it in the messageToSend method (that wasn't in the sample either). In the Oldimon class, I have: def messageToSend(self, message): self.sendMessage(message) # Re-arm the deferred self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
On Mar 2, 2013 9:50 AM, "Benjamin BERTRAND" <beenje@gmail.com> wrote:
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something?
/Benjamin
def run_pcap(device, pcap_filter, callback):
def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id)
p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet)
class Oldimon(Protocol):
def __init__(self, factory): self.factory = factory self.line = None
def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
class OldimonFactory(ServerFactory):
def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT)))
def buildProtocol(self, addr): return Oldimon(self)
def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data)
oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Ah, but that too appears to be missing in the original code ;-) The stuff you're doing with deferreds there seems a bit strange. In your example, why not just call sendMessage when you get the packet? On Sat, Mar 2, 2013 at 2:28 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
Le 2 mars 2013 à 10:08, Laurens Van Houtven <_@lvh.cc> a écrit :
Yes, that looks okay, but that wasn't in your original sample ;-)
Yep, sorry about that. I was more focused on the ServerFactory and Protocol. The pcap in a thread comes from the link I mentioned in my first post: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet... But I know, it's better to put everything in one post. People shouldn't have to click links.
I'm on my phone at the moment which isn't great for code review, but it looks like you only fire one deferred per line?
There is a specific deferred by line. I re-arm it in the messageToSend method (that wasn't in the sample either). In the Oldimon class, I have:
def messageToSend(self, message): self.sendMessage(message) # Re-arm the deferred self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
On Mar 2, 2013 9:50 AM, "Benjamin BERTRAND" <beenje@gmail.com> wrote:
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something?
/Benjamin
def run_pcap(device, pcap_filter, callback):
def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id)
p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet)
class Oldimon(Protocol):
def __init__(self, factory): self.factory = factory self.line = None
def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
class OldimonFactory(ServerFactory):
def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT)))
def buildProtocol(self, addr): return Oldimon(self)
def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data)
oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh
Le 2 mars 2013 à 14:53, Laurens Van Houtven <_@lvh.cc> a écrit :
Ah, but that too appears to be missing in the original code ;-)
The stuff you're doing with deferreds there seems a bit strange. In your example, why not just call sendMessage when you get the packet?
If I had only one server yes. But the thing is I have to send the message to a different server depending on the line id. That was my initial problem. I don't see how I could call the sendMessage method corresponding to a specific server directly. Or?
On Sat, Mar 2, 2013 at 2:28 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
Le 2 mars 2013 à 10:08, Laurens Van Houtven <_@lvh.cc> a écrit :
Yes, that looks okay, but that wasn't in your original sample ;-)
Yep, sorry about that. I was more focused on the ServerFactory and Protocol. The pcap in a thread comes from the link I mentioned in my first post: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet... But I know, it's better to put everything in one post. People shouldn't have to click links.
I'm on my phone at the moment which isn't great for code review, but it looks like you only fire one deferred per line?
There is a specific deferred by line. I re-arm it in the messageToSend method (that wasn't in the sample either). In the Oldimon class, I have:
def messageToSend(self, message): self.sendMessage(message) # Re-arm the deferred self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
On Mar 2, 2013 9:50 AM, "Benjamin BERTRAND" <beenje@gmail.com> wrote:
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something?
/Benjamin
def run_pcap(device, pcap_filter, callback):
def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id)
p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet)
class Oldimon(Protocol):
def __init__(self, factory): self.factory = factory self.line = None
def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
class OldimonFactory(ServerFactory):
def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT)))
def buildProtocol(self, addr): return Oldimon(self)
def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data)
oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
I'm guessing that this is another question that will be solved as soon as I see the code (perhaps you should put all your code up somewhere); but all I do know is that all Deferreds buy you is an abstraction for organizing callbacks; it's not a dispatch mechanism (and if you're using it as one now, you do have dispatch logic, it just lives somewhere else). On Sat, Mar 2, 2013 at 3:25 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
Le 2 mars 2013 à 14:53, Laurens Van Houtven <_@lvh.cc> a écrit :
Ah, but that too appears to be missing in the original code ;-)
The stuff you're doing with deferreds there seems a bit strange. In your example, why not just call sendMessage when you get the packet?
If I had only one server yes. But the thing is I have to send the message to a different server depending on the line id. That was my initial problem. I don't see how I could call the sendMessage method corresponding to a specific server directly. Or?
On Sat, Mar 2, 2013 at 2:28 PM, Benjamin BERTRAND <beenje@gmail.com>wrote:
Le 2 mars 2013 à 10:08, Laurens Van Houtven <_@lvh.cc> a écrit :
Yes, that looks okay, but that wasn't in your original sample ;-)
Yep, sorry about that. I was more focused on the ServerFactory and Protocol. The pcap in a thread comes from the link I mentioned in my first post: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet... But I know, it's better to put everything in one post. People shouldn't have to click links.
I'm on my phone at the moment which isn't great for code review, but it looks like you only fire one deferred per line?
There is a specific deferred by line. I re-arm it in the messageToSend method (that wasn't in the sample either). In the Oldimon class, I have:
def messageToSend(self, message): self.sendMessage(message) # Re-arm the deferred self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
On Mar 2, 2013 9:50 AM, "Benjamin BERTRAND" <beenje@gmail.com> wrote:
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something?
/Benjamin
def run_pcap(device, pcap_filter, callback):
def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id)
p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet)
class Oldimon(Protocol):
def __init__(self, factory): self.factory = factory self.line = None
def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
class OldimonFactory(ServerFactory):
def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT)))
def buildProtocol(self, addr): return Oldimon(self)
def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data)
oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh
Le 2 mars 2013 à 15:33, Laurens Van Houtven <_@lvh.cc> a écrit :
I'm guessing that this is another question that will be solved as soon as I see the code (perhaps you should put all your code up somewhere); but all I do know is that all Deferreds buy you is an abstraction for organizing callbacks; it's not a dispatch mechanism (and if you're using it as one now, you do have dispatch logic, it just lives somewhere else).
The dispatch is done in the pcapDataReceived method (in the ServerFactory) thanks to the dictionary of deferred (using the line id as key). And each line is associated to a server on a specific port. It's maybe a bit strange, but does what I want. Here is the code if you are interested: http://pastebin.com/VeQgQ85z Unfortunately, I can't give any data to test it (I only have live data that I don't think I can share)...
On Sat, Mar 2, 2013 at 3:25 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
Le 2 mars 2013 à 14:53, Laurens Van Houtven <_@lvh.cc> a écrit :
Ah, but that too appears to be missing in the original code ;-)
The stuff you're doing with deferreds there seems a bit strange. In your example, why not just call sendMessage when you get the packet?
If I had only one server yes. But the thing is I have to send the message to a different server depending on the line id. That was my initial problem. I don't see how I could call the sendMessage method corresponding to a specific server directly. Or?
On Sat, Mar 2, 2013 at 2:28 PM, Benjamin BERTRAND <beenje@gmail.com> wrote:
Le 2 mars 2013 à 10:08, Laurens Van Houtven <_@lvh.cc> a écrit :
Yes, that looks okay, but that wasn't in your original sample ;-)
Yep, sorry about that. I was more focused on the ServerFactory and Protocol. The pcap in a thread comes from the link I mentioned in my first post: http://dound.com/2009/09/integrating-twisted-with-a-pcap-based-python-packet... But I know, it's better to put everything in one post. People shouldn't have to click links.
I'm on my phone at the moment which isn't great for code review, but it looks like you only fire one deferred per line?
There is a specific deferred by line. I re-arm it in the messageToSend method (that wasn't in the sample either). In the Oldimon class, I have:
def messageToSend(self, message): self.sendMessage(message) # Re-arm the deferred self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
On Mar 2, 2013 9:50 AM, "Benjamin BERTRAND" <beenje@gmail.com> wrote:
Le 2 mars 2013 à 04:34, exarkun@twistedmatrix.com a écrit :
On 1 Mar, 09:52 pm, beenje@gmail.com wrote:
Thanks for the answer!
I was hoping to avoid having to put something like AMP in place, because it looked a bit overkill for my case. I think I actually found a way :-)
Unfortunately, it looks like the code that you shared will only work accidentally (if at all). You cannot use Twisted APIs except in the reactor thread. You will at least need to add in some code to send data back to the reactor thread before you use Twisted APIs (such as `Deferred.callback`).
In run_pcap, I call reactor.callFromThread(callback, x25_data, line_id). See below. That seems to work with the tests I did. Am I missing something?
/Benjamin
def run_pcap(device, pcap_filter, callback):
def analyse_packet(hdr, data): # check the data reactor.callFromThread(callback, x25_data, line_id)
p = pcapy.open_live(device, 65535, 1, 100) p.setfilter(pcap_filter) p.loop(-1, analyse_packet)
class Oldimon(Protocol):
def __init__(self, factory): self.factory = factory self.line = None
def connectionMade(self): # Check the server port to get the line # associated to this protocol port = self.transport.getHost().port self.line = LINES_PORT[port] # Add the callback for this line self.factory.deferred[self.line] = defer.Deferred() self.factory.deferred[self.line].addCallback(self.messageToSend)
class OldimonFactory(ServerFactory):
def __init__(self, device, pcap_filter): # pcapDataReceived callback is called everytime a message # is received reactor.callInThread(run_pcap, device, pcap_filter, self.pcapDataReceived) # Dict with a deferred for each line self.deferred = dict(zip(LINES_PORT.values(), [None] * len(LINES_PORT)))
def buildProtocol(self, addr): return Oldimon(self)
def pcapDataReceived(self, data, line): if self.deferred[line] is not None: # Fire the callback for line d, self.deferred[line] = self.deferred[line], None d.callback(data)
oldimon_factory = OldimonFactory(device, pcap_filter) for port in LINES_PORT.keys(): reactor.listenTCP(port, oldimon_factory) reactor.run()
Jean-Paul
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
-- cheers lvh _______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Benjamin BERTRAND <beenje@gmail.com> writes:
Le 2 mars 2013 à 15:33, Laurens Van Houtven <_@lvh.cc> a écrit :
I'm guessing that this is another question that will be solved as soon as I see the code (perhaps you should put all your code up somewhere); but all I do know is that all Deferreds buy you is an abstraction for organizing callbacks; it's not a dispatch mechanism (and if you're using it as one now, you do have dispatch logic, it just lives somewhere else).
The dispatch is done in the pcapDataReceived method (in the ServerFactory) thanks to the dictionary of deferred (using the line id as key). And each line is associated to a server on a specific port.
Instead sticking a deferred in that dictionary, you could just stick the `Oldimon` protocol instance, or the bound method (i.e. `self.sendMessage`) in that dictionary. In which case `messageToSend` becomes obsolete, since you don't need to rearm it each time. Tom
Le 2 mars 2013 à 19:12, Tom Prince <tom.prince@ualberta.net> a écrit :
Benjamin BERTRAND <beenje@gmail.com> writes:
Le 2 mars 2013 à 15:33, Laurens Van Houtven <_@lvh.cc> a écrit :
I'm guessing that this is another question that will be solved as soon as I see the code (perhaps you should put all your code up somewhere); but all I do know is that all Deferreds buy you is an abstraction for organizing callbacks; it's not a dispatch mechanism (and if you're using it as one now, you do have dispatch logic, it just lives somewhere else).
The dispatch is done in the pcapDataReceived method (in the ServerFactory) thanks to the dictionary of deferred (using the line id as key). And each line is associated to a server on a specific port.
Instead sticking a deferred in that dictionary, you could just stick the `Oldimon` protocol instance, or the bound method (i.e. `self.sendMessage`) in that dictionary. In which case `messageToSend` becomes obsolete, since you don't need to rearm it each time.
Good point! I guess I should try to think more "Python" before trying to think "Twisted" :-) Thanks Benjamin
Tom
participants (7)
-
Benjamin BERTRAND
-
exarkun@twistedmatrix.com
-
Glyph
-
Laurens Van Houtven
-
Phil Mayers
-
Tom Prince
-
Tristan Seligmann