1
\$\begingroup\$

I am trying to understand how we can use generator based coroutines to write asynchronous code in a sequential style without using any of the new features in Python so that the fundamental idea is clear.

Is this approach fine? One thing I can probably improve upon is the idea of using other coroutines. Is there any feedback on this code?

#!/usr/bin/python

import socket
import selectors

select = selectors.DefaultSelector()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

hostname = socket.gethostname()

print("Server starting on port 9000")

s.bind((hostname, 9000))

s.listen(5)

# library starts here   

class Deferred(object):

    def __init__(self):
        self.state = "pending"
        self.value = None
        self.task = None

    def done(self, value):
        self.state = "complete"
        self.value = value
        if self.task:
            self.task(value)

    def future(self, task):
        if self.state == "complete":
            self.task(value)
        else:
            self.task = task

def watch(fd, event):
    deferred = Deferred()
    select.register(fd, event, deferred.done)
    return deferred

def unwatch(fd):
    select.unregister(fd)

def run_till_complete(g):
    try:
        d = g.send(None)
        d.future(lambda value: run_till_complete(g))
    except StopIteration:
        pass

# library ends here

# application starts here

def handle_client(s):
    c, a = s.accept()
    message = "Connection recieved from %s" % str(a)
    print(message)
    run_till_complete(echo_client(c))

select.register(s, selectors.EVENT_READ, handle_client)

def echo_client(c):
    while True:
        yield watch(c, selectors.EVENT_READ)
        unwatch(c)
        r = c.recv(1024)
        yield watch(c, selectors.EVENT_WRITE)
        unwatch(c)
        c.send(bytes(r))

# application ends here

# event loop starts here

try:
    while True:
        events = select.select()
        for key, mask in events:
            callback = key.data
            callback(key.fileobj)
except KeyboardInterrupt:
    print(" recieved")
finally:
    print("Server stopping on port 9000")
    select.unregister(s)
    s.close()

# event loop ends here

A simple client looks like this:

#!/usr/bin/python

import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

hostname = socket.gethostname()

client_socket.connect((hostname, 9000))

chunks = []

while True:
    message = bytes(input("Message: "), 'utf-8')
    client_socket.send(message)
    print(client_socket.recv(1024))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.