Let’s write a simple tcp server/terminal. Usually my way of thinking must be adapted to the programming language being used. This is my small attempt to modify how the language works to my thinking. I call it event based problem solving.
First of all, this is not a typical example of writing a tcp server in python. As a beginner you might still be able to get some knowledge, but to be able to understand the whole example you must understand threads and python decorators.
I want a program that listens on a tcp port. When a remote connection is established it will be connected to the terminal so that when I type on the terminal it is sent to the remote machine and when the remote machine send text it is printed on the terminal. Think of it as a reversed telnet client.
My intuitive solution
To make this work I need one function that listens for new connections, waitConnect(). When I get this new connection I initiate two new functions. First socket_reader() which read all incoming data and print it to the screen, stdout.write() and then terminal_reader() which will read what I type and send it to the connection, con.send(). Here is what it looks like:
The code
A simplified version, without error checking, looks like this:
def terminal_reader(con):
while True:
line = sys.stdin.readline()
con.send(line.encode('utf-8'))
def socket_reader(con):
while True:
data = con.recv(1)
sys.stdout.write(data.decode('utf-8'))
def waitConnect(s):
while True:
connection, address = s.accept() #
sr = socket_reader(connection)
tr = terminal_reader(connection)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1", 8082))
s.listen(5)
waitConnect(s)
Simple right?
Everyone who is somewhat familiar with programming have already noticed that there is something missing. Ordinary functions would not work alone.
Many of the internal function calls within our functions are blocking, such as accept(), readline() and recv(). Without threads it is impossible to use blocking functions and still have the program responsive to both tcp input and terminal input at the same time.
Event magic
To make this possible we will do some slight modification to our program. We add the decorator @ed.function to all our three functions and in the end of our code we add ed.join(). Finally we must also add an import ed in the beginning of the code.
The ed is a library I wrote in python to accomplish something similar to the example above. It initiates a queue and a number of worker threads. The @ed.function decoration modifies the functions so that instead of being called immediately they will be queued. The worker threads will then run each function call. Finally the ed.join() will wait until the queue is empty and then exit.
What we have now is events in the form of function calls.
This is a proof-of-concept with only the basic functions as presented here. The code can be downloaded using “git clone http://src.endnode.se/git/event-demo“.

