If you are familiar with socket programming, you would be aware that send and recv are usually blocking calls. This means that the code execution will be blocked until they are successfully resolved.
This prevents us from writing TCP servers that can respond to multiple clients. However, there are different ways where we can write our own web server that can handle multiple connections.
Using select system call
The .select()
method allows you to check for I/O completion on more than one socket. This enables you to use more than one socket for a port and multiplex connection using the system call.
Server with Threads
Another way to handle multiple client connections is to allocate a single thread to each of the clients.
import socket | |
import threading | |
class ThreadedServer: | |
def __init__(self, host_name="localhost", port_num=6379, reuse_port=True): | |
self.host_name = host_name | |
self.port_num = port_num | |
self.reuse_port = reuse_port | |
self.init_server() | |
def init_server(self): | |
self.socket = socket.create_server((self.host_name, self.port_num), reuse_port=self.reuse_port) | |
# self.socket.setblocking(False) # raises error for some reason | |
print(f"Listening on {(self.host_name, self.port_num)}") | |
def accept(self): | |
conn, addr = self.socket.accept() | |
# conn.setblocking(False) # raises error for some reason | |
print(f"Connected to {addr}") | |
return conn, addr | |
def __reply_to_ping(self, conn, addr): | |
while True: | |
try: | |
conn.recv(1024) # wait for client to send data | |
self.__send(conn, b"+PONG\r\n") | |
except ConnectionError: | |
print(f"Disconnected from {addr}") | |
break # Stop serving if the client connection is closed | |
def __send(self, conn, data): | |
conn.sendall(data) | |
def listen_for_connections(self): | |
while True: | |
conn, addr = self.accept() | |
threading.Thread(target=self.__reply_to_ping, args=(conn, addr,)).start() | |
def __del__(self): | |
self.socket.close() | |
if __name__ == "__main__": | |
s = ThreadedServer() | |
s.listen_for_connections() |
Async Server with lower level calls
Contrary to popular opinion, IMHO Async is another way of writing multithreaded code. The difference between using threads and async, with threads it is easier to write buggy code. Also, sometimes it is harder to reason. Async makes it relatively easier to write code that can handle concurrent requests.
Async Server with higher level calls
This is the same as above, except this uses more convenient high level functions as opposed to using lower level socket APIs.
I hope you found this helpful. In case you know of another way please do leave a comment.
0 Comments