Are twisted RPCs guaranteed to arrive in order? - python

I'm using twisted to implement a client and a server. I've set up RPC between the client and the server. So on the client I do protocol.REQUEST_UPDATE_STATS(stats), which translates into sending a message with transport.write on the client transport that is some encoded version of ["update_stats", stats]. When the server receives this message, the dataReceived function on the server protocol is called, it decodes it, and calls a function based on the message, like CMD_UPDATE_STATS(stats) in this case.
If, on the client, I do something like:
protocol.REQUEST_UPDATE_STATS("stats1")
protocol.REQUEST_UPDATE_STATS("stats2")
...am I guaranteed that the "stats1" message arrives before the "stats2" message on the server?
UPDATE: Edited for more clarity. But now the answer seems obvious - no way.

They will arrive in the order that the request is received by the Python process. This includes the connection setup time plus the packets containing the request data. So no, this is not guaranteed to be the order that the sending processes sent the request, because of network latency, dropped packets, sender-side packet queuing, etc. "In-order" is also loosely defined for distributed systems.
But yes, in general you can count on them being delivered in-order as long as they're separated by a relatively large amount of time (100's of ms over the internet).

Related

Does setting socket timeout cancel the initial request

I have a request that can only run once. At times, the request takes much longer than it should.
If I were to set a default socket timeout value (using socket.setdefaulttimeout(5)), and it took longer than 5 seconds, will the original request be cancelled so it's safe to retry (see example code below)?
If not, what is the best way to cancel the original request and retry it again ensuring it never runs more than once.
import socket
from googleapiclient.discovery import build
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception_type
#retry(
retry=retry_if_exception_type(socket.timeout),
wait=wait_fixed(4),
stop=stop_after_attempt(3)
)
def create_file_once_only(creds, body):
service = build('drive', 'v3', credentials=creds)
file = service.files().create(body=body, fields='id').execute()
socket.setdefaulttimeout(5)
create_file_once_only(creds, body)
It's unlikely that this can be made to work as you hope. An HTTP POST (as with any other HTTP request) is implemented by sending a command to the web server, then receiving a response. The python requests library encapsulates a lot of tedious parts of that for you, but at the core, it's going to do a socket send followed by a socket recv (it may of course require more than one send or recv depending on the size of the data).
Now, if you were able to connect to the web server initially (again, this is taken care of for you by the requests library but typically only takes a few milliseconds), then it's highly likely that the data in your POST request has long since been sent. (If the data you are sending is megabytes long, it's possible that it's only been partially sent, but if it is reasonably short, it's almost certainly been sent in full.)
That in turn means that in all likelihood the server has received your entire request and is working on it or has enqueued your request to work on it eventually. In either case, even if you break the connection to the server by timing out on the recv, it's unlikely that the server will actually even notice that until it gets to the point in its execution where it would be sending its response to your request. By that point, it has probably finished doing whatever it was going to do.
In other words, your socket timeout is not going to apply to the "HTTP request" -- it applies to the underlying socket operations instead -- and almost certainly to the recv part on the tail end. And just breaking the socket connection doesn't cancel the HTTP request.
There is no reliable way to do what you want without designing a transactional protocol with the close cooperation of the HTTP server.
You could do something (with the cooperation of the HTTP server still) that could do something approximating it:
Create a unique ID (UUID or the like)
Send a request to the server that contains that UUID along with the other account info (name, password, whatever else)
The server then only creates the account if it hasn't already created an account with the same unique ID.
That way, you can request the operation multiple times, but know that it will only actually be implemented once. If asked to do the same operation a second time, the server would simply respond with "yep, already did that".

Allowing message dropping in websockets

Is there a simple method or library to allow a websocket to drop certain messages if bandwidth doesn't allow? Or any one of the following?
to measure the queue size of outgoing messages that haven't yet reached a particular client
to measure the approximate bitrate that a client has been receiving recent messages at
to measure the time that a particular write_message finished being transmitted to the client
I'm using Tornado on the server side (tornado.websocket.WebSocketHandler) and vanilla JS on the client side. In my use case it's really only important that the server realize that a client is slow and throttle its messages (or use lossier compression) when it realizes that condition.
You can implement this on top of what you have by having the client confirm every message it gets and then use that information on the server to adapt the sending of messages to each client.
This is the only way you will know which outgoing messages haven't yet reached the client, be able to approximate bitrate or figure out the time it took for the message to reach the client. You must consider that the message back to the server will also take time and that if you use timestamps on the client, they will likely not match your servers as clients have their time set incorrectly more often than not.

How to distinguish sever responses from announcement messages the server sends when using twisted library?

The situation is that I want to make client application which connects to a server (it is a custom TCP protocol), maintain persistent connection and at occasions send some requests, receive responses. So far something that I can achieve easily with python twisted library.
However, in this case the server is quite chatty, and can decide at any time that it will send an announcement message to all its connected clients. From the protocol point of view, there is a field (let's call it packetid) in the packet header that allows me to match request responses, and to distinguish the announcement packets from those, no problem from protocol point of view.
Now I am thinking how to implement code that will be able to handle this, to distinguish incoming responses from server announcements. My idea is to simply maintain a dictionary in the custom Protocol implementation, and store the Deferred objects there for each request (packetid would be the key). Once I receive individual message through receivedData, I use the packetid field given in my packet to lookup in the dictionary, and call corresponding callbacks for corresponding Deferred, if it is a response to some of previous requests, otherwise react to it as a server announcement message.
Is this solution alright, or is there some better solution, perhaps utilizing some of the already provided twisted mechanism? Also is there some existing protocol that has same characteristics, a protocol that needs within same connection to distinguish responses from other messages (so that I could inspire by its implementation)?

how does a server execute different tasks based on client input?

I am currently implementing a socket server using Python's socketServer module. I am struggling to understand how a client 'signals' the server to perform certain tasks.
As you can tell, I am a beginner in this area. I have looked at many tutorials, however, these only tell you how to perform singular tasks in the server e.g. modify a message from the client and send it back.
Ideally what I want to know is there a way for the client to communicate with the server to perform different kinds of tasks.
Is there a standard approach to this issue?
Am I even using the correct type of server?
I was thinking of implementing some form of message passing from the client that tells the server which task it should perform.
I was thinking of implementing some form of message passing from the client that tells the server which task it should perform.
That's exactly what you need: an application protocol.
A socket (assuming a streaming Internet socket, or TCP) is a stream of bytes, nothing more. To give those bytes any meaning, you need a protocol that determines which byte (or sequence thereof) means what.
The main problem to tackle is that the stream that such a socket provides has no notion of "messages". So when one party sends "HELLO", and "BYE" after that, it all gets concatenated into the stream: "HELLOBYE". Or worse even, your server first receives "HELL", followed by "OBYE".
So you need message framing, or rules how to interpret where messages start and end.
You generally don't want to invent your own application protocol. Usually HTTP or other existing protocols are leveraged to pass messages around.

Design question on Python network programming

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.
"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.
"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.

Categories

Resources