views:

148

answers:

2

I'm currently writing a project in Python which has a client and a server part. I have troubles with the network communication, so I need to explain some things...

The client mainly does operations the server tells him to and sends the results of the operations back to the server. I need a way to communicate bidirectional on a TCP socket.

Current Situation

I currently use a LineReceiver of the Twisted framework on the server side, and a plain Python socket (and ssl) on client side (because I was unable to correctly implement a Twisted PushProducer). There is a Queue on the client side which gets filled with data which should be sent to the server; a subprocess continuously pulls data from the queue and sends it to the server (see code below).

This scenario works well, if only the client pushes its results to the manager. There is no possibility the server can send data to the client. More accurate, there is no way for the client to receive data the server has sent.

The Problem

I need a way to send commands from the server to the client.

I thought about listening for incoming data in the client loop I use to send data from the queue:

def run(self):
    while True:
        data = self.queue.get()
        logger.debug("Sending: %s", repr(data))
        data = cPickle.dumps(data)
        self.socket.write(data + "\r\n")
        # Here would be a good place to listen on the socket

But there are several problems with this solution:

  • the SSLSocket.read() method is a blocking one
  • if there is no data in the queue, the client will never receive any data

Yes, I could use Queue.get_nowait() instead of Queue.get(), but all in all it's not a good solution, I think.

The Question

Is there a good way to achieve this requirements with Twisted? I really do not have that much skills on Twisted to find my way round in there. I don't even know if using the LineReceiver is a good idea for this kind of problem, because it cannot send any data, if it does not receive data from the client. There is only a lineReceived event.

Is Twisted (or more general any event driven framework) able to solve this problem? I don't even have real event on the communication side. If the server decides to send data, it should be able to send it; there should not be a need to wait for any event on the communication side, as possible.

+1  A: 

"I need a way to send commands from the server to the client."

Don't do this. It inverts the usual meaning of "client" and "server". Clients take the active role and send stuff or request stuff from the server.

Is Twisted (or more general any event driven framework) able to solve this problem?

It shouldn't. You're inverting the role of client and server.

If the server decides to send data, it should be able to send it;

False, actually.

The server is constrained to wait for clients to request data. That's generally the accepted meaning of "client" and "server".


"One to send commands to the client and one to transmit the results to the server. Does this solution sound more like a standard client-server communication for you?"

No.

If a client sent messages to a server and received responses from the server, it would meet more usual definitions.

Sometimes, this sort of thing is described as having "Agents" which are -- each -- a kind of server and a "Controller" which is a single client of all these servers.

The controller dispatches work to the agents. The agents are servers -- they listen on a port, accept work from the controller, and do work. Each Agent must do two concurrent things (usually via the select API):

  • Monitor a well-known socket on which it will receive work from the one-and-only client.

  • Do the work (in the background).

This is what Client-Server usually means.

If each Agent is a Server, you'll find lots of libraries will support this. This is the way everyone does it.

S.Lott
+1 for concise problem analysis
knitti
Your answer is, not to do that this way, because no one does it this way? I have a problem and need a solution, i don't think questioning the problem is straightforward here. I've thought about connecting two TCP sockets, like FTP does. One to send commands to the client and one to transmit the results to the server. Does this solution sound more like a _standard_ client-server communication for you?
Manuel Faux
If you don't like the words "client" and "server" then how about "master" and "slave"? Or "manager" and "worker"? There's nothing wrong with a design that many processes connecting to one and then receiving commands from it. Your "accept meanings" are needlessly restricted.
Jean-Paul Calderone
S.Lott, you might want to read up on the design and terminology of the X protocol. The words "client" and "server" do not always mean what you seem to think they mean.
Forest
Having a clear semantics which side is supposed to do what actually helps in keeping the software implementation sane, and problem free. Having a server push data to the client (vs. the client polling from the server) will bring you problems down the road.
knitti
If you don't like the way I use servers and clients, please tell me another way to solve my problem: A manager tells its workers to do a job and they continuously send it the results of the work until the manager tells them to stop or to do something else.
Manuel Faux
Request from the manager a chunk of work, do it and report back when you're done. The difference seems subtle, but your approach will have scaling issues and hard to troubleshoot communication issues (been there, done that)
knitti
I actually this a bit back: it depends. Pull architectures are easier to build up, I think.
knitti
_The difference seems subtle..._ The difference to what? What is the difference between our approaches? I currently do exactly what you are describing, except there is no _done_. The workers get jobs which are not done until the manager tells them to stop.
Manuel Faux
@forest: The X client applications make requests of the X server. The X server (running on your desktop) has events queued which the X client application must accept. I think the meanings are the same. The X server can't communicate randomly to a client. My understanding is that the client -- effectively -- polls the X server for mouse and keyboard events.
S.Lott
+1  A: 

"I don't even know if using the LineReceiver is a good idea for this kind of problem, because it cannot send any data, if it does not receive data from the client. There is only a lineReceived event."

You can send data using protocol.transport.write from anywhere, not just in lineReceived.

Forrest
Yes, this is the problem I encountered with the `LineReceiver`.
Manuel Faux
And ... I'm proposing a solution - call `protocol.transport.write` from somewhere other than `lineReceived`.
Forrest