Creating a Simple Server from Sockets
We'll see how we go from a socket to a simple server, in Python.
What Is a Server?
When you learn web development, you learn to build a server. A server is a program that listens for incoming requests. You probably learned about servers with a web server, which means the communication follows the Hypertext Transfer Protocol.
Not all servers are web servers, nor is all communication done with HTTP. But, all communication is based on sockets. Therefore, both HTTP and web servers are built on top of sockets.
What Is a Socket?
Imagine a computer program like a house; then the door would be the socket. When a house wants to send data to another house, it opens the door and sends it. The other program opens the door to receive the data.
The Transport Layer
What happens between doors is up to the Transport Layer. So the transport layer would be the postman in our metaphor.
IP and Port
How does the transport layer know where to go with the data? To which house? This information is in the data package, and it has two parts: the IP address and the port.
The IP address is a numerical label that identifies a computer in a network (such as 192.0.2.1). What if that computer is running more than one program? How does the computer know to which program the data belongs to?
The port is the program identifier. Once the package reaches the computer, the operating system delivers the data to the specific program based on the port number. The port is displayed commonly after the IP address, separated by a colon: 192.0.2.1:80.
Show Me The Code
We will build and run two different programs that share some information through TCP. TCP is an example of the transport layer mentioned before. We won’t go into the details; it’s enough for us to know that we have a sender (or client) and the receiver (or server) in TCP.
Python Client
This is a simple code in Python to start a connection and send a message as client:
We first create a socket with
server_socket = socket(AF_INET, SOCK_STREAM)
.AF_INET
indicates the underlying network IPv4SOCK_STREAM
means TCP type socket.client_socket.connect(server_id', server_port))
establishes the connection. This is specific to TCP, which needs a handshake between the two programs before sending any data.server_ip
andserver_port
need to be known by the client. We can’t send data to a program if we don’t know where it is.client_socket.send('Hello, server')
sends the data. The program puts it out of the door; the OS then sends it through TCP.The program then stops here.
client_socket.recv(1024)
is called when this program receives something in its socket.client_socket.close()
closes the connection.The calls to
.decode
and.encode
are needed because the sockets only care about bytes, not about strings. Callingencode
converts the string to bytes, whereasdecode
converts it back to a string. This is also needed in the server.
Python Server
Let’s now see the code to receive the data:
server_socket = socket(AF_INET, SOCK_STREAM)
same as before, we create a socket.server_socket.bind(('', server_port))
here we define the port of the program.server_port
needs to be the same port the client sends it to. In this case, both have “12000”.server_socket.listen(1)
we tell the socket to open the door if something arrives.connection_socket, addr = server_socket.accept()
. When a client knocks on the door, the program invokes theaccept
method, which creates a new socket in the server dedicated to this particular client.The client socket and the new socket complete the TCP handshake, and a new socket is created for this, the
connection_socket
.data_received = connection_socket.recv(1024)
. After the handshake, the server receives the data.connection_socket.send("hello from the server!")
the new socket replies with some data.connection_socket.close()
we close the connection of the newly created socket. Not theserver_socket
.
Server and Client interaction
Let’s take a look at how the sockets play and connect with each other:
Executing client and server
To execute both programs, we need two terminal windows:
One runs the server with
python3 server.py
.The other executes the client with
python3 client.py
.
Yet, if we execute the client again, we don’t receive anything. This is because the receiver program has been closed. But, this is not how a server is supposed to work.
Fixing the Server
We don’t want the server program to end. We need to be always open and listen to the door. How do we accomplish this?
I found the answer a little disturbing: “with an infinite loop.”
After receiving data from one client, we want to connect to the next one; therefore, we want to return to connection_socket, addr = server_socket.accept()
.
The while True:
like ensures that this program never ends. Instead, it always comes back at the command server_socket.accept()
, which starts the handshake with a client.
This infinite loop converts a simple program that receives data into a server that listens to incoming requests.
From Server to Web Server
Web Servers use the HTTP Protocol to exchange data, and we used sockets to send a simple text through TCP. To build a fully functional HTTP server, we need to implement the protocol both on the client and the server side.
This work is done by many tools and libraries, from fetch in the browser to flask in Python. But, behind those libraries, sockets interact the same way we learned here.
Note the sockets explained here are not Web Sockets. Web Sockets is another protocol used on the internet. Both HTTP and Web Sockets use sockets, the doors of running programs.
Sockets are one of the underlying technologies enabling the internet.
Resources
Most of the examples come from “Computer Networking. A Top-Down Approach.”
If you like this post, consider sharing it with your friends on twitter or forwarding this email to them 🙈
Don't hesitate to reach out to me if you have any questions or see an error. I highly appreciate it.
And thanks to Michal and Sebastià for reviewing this article 🙏