This article provides a brief tutorial on how to code sockets in Python. Socket programming can be a bit confusing at first, but, fortunately for us, Python makes it really easy.

I assume that you already have a basic understanding of Python. You can download the code for this tutorial from this GitHub repository.

Before plunging into implementation, let’s review a bit of theory first to acquire basic notions about sockets.

What are sockets?

Sockets are at the basis of network communication between computers. Every time you request a webpage , a socket is opened and used for transferring information from the server to the client. For example, when you type http://www.facebook.com, your web browser opens a socket, which connects to the Facebook server and sends it an HTTP request to fetch the content of the Facebook homepage.Once the socket receives the data, the browser shows you the content. To be a bit more formal, we can define a socket as a software endpoint that establishes bidirectional communication between a server and a client.

When talking about sockets, we usually refer to sockets in an Internet Protocol (IP) network. These sockets typically use TCP (Transmission Control Protocol) as the protocol for handling 1-to-1 connections, between two nodes in a network. There are also UDP (User Datagram Protocol) sockets, which can be easily implemented in Python. However, for this tutorial we’ll focus on TCP sockets only.

Sockets are associated with a socket address, which consists of an IP address and a port number. By using the same port number, a server and a client sockets can easily communicate. The process of association of a socket with a socket address is called binding.

Client and server sockets

There are both client and server sockets. Client sockets are used to send requests to the server and to receive the server’s response. As the name suggests, server sockets typically serve resources to a network of client sockets.

In order to serve more than one client at a time, the server socket should be multi-threaded. With this architecture, the server creates a thread for each connection it establishes from a client. Simply speaking, a thread is a sequence of instructions that can run independently of any other threads.

Now that we know a bit of the theory behind sockets, let’s begin implementing them in Python!

Coding a client socket

:To create a functioning client socket which is able to send/receive data to/from a server, we’ll follow the steps below:

Create a socket Connect to a server Send data Receive data

Create a socket

We start out creating a socket. Luckily, doing this in Python is as simple as invoking the socket function from the socket module.

# a simple client socket import socket # define socket address TCP_IP = '127.0.0.1' # ip of the server we want to connect to TCP_PORT = 5000 # port used for communicating with the server # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully."

The two arguments we pass to the socket function identify the family type and the socket type:

socket.AF_INET specifies that the socket we’ve created will communicate using addresses of the type IPv4.

specifies that the socket we’ve created will communicate using addresses of the type IPv4. socket.SOCK_STREAM tells the socket function that we want to use the TCP protocol to handle connections.

Now you’ve created a socket. The next step is to connect to a server to establish a communication. For this purpose, we’ll use the server socket that we’ll develop next, that will run on localhost (127.0.0.1).

Connect to a server

Connecting to a server is very simple. You just need to pass the socket address (server ip and port) to the connect function.

# a simple client socket import socket # define socket address TCP_IP = '127.0.0.1' # ip of the server we want to connect to TCP_PORT = 5000 # port used for communicating with the server # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # connect to server s.connect((TCP_IP, TCP_PORT)) print "Established connection with the server."

Send data

Now, it’s time to send some data over to the server. To do this, we use the send function. This function takes as argument the message we’d like to send.

# a simple client socket import socket # define socket address TCP_IP = '127.0.0.1' # ip of the server we want to connect to TCP_PORT = 5000 # port used for communicating with the server # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # connect to server s.connect((TCP_IP, TCP_PORT)) print "Established connection with the server." message = "I've been sent from the client!" # send message to the server s.send(message) print "Message sent to server."

Receive data

Up until now, we’ve created a socket, opened a connection with the server and sent a request. Assuming the remote server has sent a reply, we now need to receive and read the data.

To do this, we simply use the recv function which returns a string representing the data received. We have to pass a value to recv which specifies the maximum amount of data that can be received at once, i.e., the buffer size.

# a simple client socket import socket # define socket address TCP_IP = '127.0.0.1' # ip of the server we want to connect to TCP_PORT = 5000 # port used for communicating with the server BUFFER_SIZE = 1024 # buffer size used when receiving data # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # connect to server s.connect((TCP_IP, TCP_PORT)) print "Established connection with the server." message = "I've been sent from the client!" # send message to the server s.send(message) print "Message sent to server." # receive data from server data = s.recv(BUFFER_SIZE) print "Here's the message received from the server:" print data

Client socket: Recap

The role of a client socket is to fetch information from a server. To implement a client socket in Python we’ve followed four steps:

Instantiate a socket Establish connection between client socket and server Send a data request Receive the reply from the server

Now that we have a functioning client socket, the next step is to create a server that can send data back to our client program when asked to.

Coding a server socket

The role of a server socket is to wait and listen for incoming connections and to distribute resources to clients. To code a server socket we’ll follow these steps:

Create a socket Bind socket to an address Listen for connections Handle connections Read client request and reply

We won’t go through point no. 1, as we already covered how to open a socket in the case of a client.

Bind socket to an address

After you create a socket, you should bind it to an address and to a port using the bind function.

# a simple server socket import socket # define socket address TCP_IP = '0.0.0.0' # consider all possible incoming IPs TCP_PORT = 5000 # port used for communicating with the client BUFFER_SIZE = 1024 # buffer size used when receiving data # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # bind socket s.bind((TCP_IP, TCP_PORT))

By binding a socket to a given port, we ensure that all the incoming data transferred through that specific port reaches the server.

A common error when doing socket programming is to use two different ports for the client and the server. If this happens, the two programs won’t establish a connection. As a tip, in case your client-server application doesn’t seem to communicate, check if the ports they use are the same. This can save you some debugging time.

Listen for connections

After binding the socket to an address, it’s time for the server to start listening for incoming connections. To put the socket in listening mode, we use the listen function. This function takes an int argument called backlog, which specifies the maximum number of connections that are kept waiting if the application is already busy.

# a simple server socket import socket # define socket address TCP_IP = '0.0.0.0' # consider all possible incoming IPs TCP_PORT = 5000 # port used for communicating with the client BUFFER_SIZE = 1024 # buffer size used when receiving data # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # bind socket s.bind((TCP_IP, TCP_PORT)) # start listening s.listen(20) print "Waiting for a connection..."

Handle connections

Once launched, the live server should be able to establish a connection with a client programme while running at any time. To achieve this, we put the server in an infinite loop. At each iteration, we look for incoming connections. If there is one, we accept the connection with the accept function.

# a simple server socket import socket # define socket address TCP_IP = '0.0.0.0' # consider all possible incoming IPs TCP_PORT = 5000 # port used for communicating with the client BUFFER_SIZE = 1024 # buffer size used when receiving data # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # bind socket s.bind((TCP_IP, TCP_PORT)) # start listening s.listen(20) print "Waiting for a connection..." # wait for connection while True: # accept connection conn, addr = s.accept() print "Connected with " + addr[0] + " " +str(addr[1])

Read client request and reply

Having a server that is able to connect with a client program but not doing anything else is pretty useless. Indeed, the next step is to read the incoming request and to send back to the client a reply.

# a simple server socket import socket # define socket address TCP_IP = '0.0.0.0' # consider all possible incoming IPs TCP_PORT = 5000 # port used for communicating with the client BUFFER_SIZE = 1024 # buffer size used when receiving data # create socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "Socket created successfully." # bind socket s.bind((TCP_IP, TCP_PORT)) # start listening s.listen(20) print "Waiting for a connection..." # wait for connection while True: # accept connection conn, addr = s.accept() print "Connected with " + addr[0] + " " + str(addr[1]) # get message from client message = conn.recv(BUFFER_SIZE) # check that there is a message if not message: break # put some logic here, if needed server_message = "I'm the message from the server..." # send message to client conn.send(server_message) s.close()

When the program exits from the loop, the socket is shut down with the close function.

Congrats! We’ve just finished creating our first server socket. It wasn’t that difficult after all.

Server socket: Recap

A server socket is used to provide client programs with the data they request. The implementation of a server socket passes through the following steps:

Open a socket Bind socket to an ip and a port Put socket to listen Accept incoming connections Read client messages and send data

Putting all together

Now that we have developed both a client and a server sockets, it’s time to let them communicate. I assume you have a client.py and a server.py files for the client and server sockets respectively.

Run the server socket from the terminal first.

$ python server.py

Once launched, the server program will wait, listening from incoming connections.

Then, open another terminal and launch client.py.

$ python client.py

The client programme will connect to the server, send a message and receive data from the server. If you’ve followed this guide step by step, the terminal from where you’ve opened the client programme should look similar to the image below.

Conclusion

In this article, I’ve presented the basics of socket programming in Python. If you’ve followed along, by now you should be able to easily create client and server sockets.

As the next step, try to experiment with what you’ve learned so far by adding more features to the simple programs presented here. Remember to check out the Python documentation on sockets, if you require more in-depth information.