Roman Dmitrienko
Roman Dmitrienko

Reputation: 4235

Is it OK to send asynchronous notifications from server to client via the same TCP connection?

As far as I understand the basics of the client-server model, generally only client may initiate requests; server responds to them. Now I've run into a system where the server sends asynchronous messages back to the client via the same persistent TCP connection whenever it wants. So, a couple of questions:

Obviously, the client has to watch both the local request queue (i.e. requests to be sent to the server), and the incoming messages from the server. Launching two threads (Rx and Tx) per connection does not feel right to me. Using select() is a major PITA here. Do I miss something?

Upvotes: 0

Views: 596

Answers (3)

cjhanks
cjhanks

Reputation: 544

When dealing with asynchronous io in python I typically use a library such as gevent or eventlet. The objective of these libraries is allow for applications written in a synchronous to be multiplexed by a back-end reactor.

This basic example demonstrates the launching of two green threads/co-routines/fibers to handle either side of the TCP duplex. The send side of the duplex is listening on an asynchronous queue.

This is all performed within a single hardware thread. Both gevent && eventlet have more substantive examples in their documentation that what I have provided below.

If you run nc -l -p 8000 you will see "012" printed out. As soon netcat is exited, this code will be terminated.

from eventlet       import connect, sleep, GreenPool
from eventlet.queue import Queue


def handle_i(sock, queue):
    while True:
        data = sock.recv(8)

        if data:
            print(data)
        else:
            queue.put(None) #<- signal send side of duplex to exit
            break

def handle_o(sock, queue):
    while True:
        data = queue.get()

        if data:
            sock.send(data)
        else:
            break

queue = Queue()
sock  = connect(('127.0.0.1', 8000))

gpool = GreenPool()
gpool.spawn(handle_i, sock, queue)
gpool.spawn(handle_o, sock, queue)

for i in range(0, 3):
    queue.put(str(i))
    sleep(1)

gpool.waitall() #<- waits until nc exits

Upvotes: 1

Ankit Tripathi
Ankit Tripathi

Reputation: 384

Yes this is very normal and Server can also send the messages to client after connection is made like in case of telnet server when you initiate a connection it sends you a message for the capability exchange and after that it asks you about your username & password.

You could very well use select() or if I were in your shoes I would have spawned a separate thread to receive the asynchronous messages from the server & would have left the main thread free to do further processing.

Upvotes: 0

Siva Tumma
Siva Tumma

Reputation: 1701

I believe what you are trying to achieve is a bit similar to jsonp. While sending to the client, send through a callback method which you know of, that is existing in client.

like if you are sending "some data xyz", send it like server.send("callback('some data xyz')");. This suggestion is for javascript because it executes the returned code as if it were called through that method., and I believe you can port this theory to python with some difficulty. But I am not sure, though.

Upvotes: 0

Related Questions