Foreword
Back in 2010, I wrote an article for beginners about sockets in Python. Now this blog has sunk into oblivion, but the article seemed to me quite useful. I found the article on a flash drive in a librovsk document, so this is not a cross-post, not a copy-paste - it is nowhere on the Internet.

What is it
First you need to figure out what are all sockets, and why we need them. As the wiki says, a socket is a software interface for providing information exchange between processes. But it is much more important not to memorize the definition, but to understand the essence. Therefore, I will try here to tell everything as much as possible and easier.
')
There are client and server sockets. It is quite easy to guess what's what. The server socket listens on a specific port, and the client socket connects to the server. After the connection has been established, data exchange begins.
Consider this with a simple example. Imagine a large room with many small windows, behind which are the girls. There are also empty windows, behind which there is no one. Those windows are ports. Where the girl stands is an open port, behind which stands some kind of application that listens to it. That is, if you go to the window with the number 9090, then you will be greeted and asked how they can help. So it is with sockets. An application is created that listens on its port. When a client establishes a connection with a server on this port, this particular application will be responsible for the operation of this client. You do not go to one window, and you will scream from the next :)
After a successful connection, the server and the client begin to exchange information. For example, the server sends a greeting and a suggestion to enter a command. The client, in turn, enters the command, the server analyzes it, performs the necessary operations and gives the result to the client.
Server
Now create two files - one for the server and the other for the client.
In Python, the socket module is used to work with sockets:
import socket
First of all, we need to create a socket:
sock = socket.socket()
There is nothing special here and this part is common for both client and server sockets. Next we will write the code for the server. This is quite logical - why do we need to write a client application, if there is no place to connect :)
Now we need to determine the host and port for our server. As for the host, we will leave the line empty so that our server is accessible to all interfaces. And we will take any port from zero to 65535. It should be noted that in most operating systems, listening to ports with numbers 0-1023 requires special privileges. I chose port 9090. Now, we associate our socket with the given host and port using the bind method, to which the tuple is transmitted, the first element (or zero if you count from zero) of which is the host, and the second is the port:
sock.bind(('', 9090))
Now we have everything ready to accept connections. Using the listen method, we will launch a listening mode for this socket. The method takes one argument - the maximum number of connections in the queue. Stress our violent fantasy and remember about the hall with windows. So this parameter determines the size of the queue. If it is installed in the unit, and someone, obviously superfluous, is still trying to adjust to it from behind, then it will be sent :) Install it in the unit:
sock.listen(1)
Well, finally, we can accept the connection using the accept method, which returns a tuple with two elements: a new socket and the client's address. It is this socket that will be used to receive and send data to the client.
conn, addr = sock.accept()
That's all. Now we have established a connection with the client and can “communicate” with it. Because we can’t know exactly what the client will send us and in what amounts, then we will receive data from him in small portions. To get the data you need to use the recv method, which takes as the argument the number of bytes to read. We will read portions of 1024 bytes (or 1 KB):
while True: data = conn.recv(1024) if not data: break conn.send(data.upper())
As we said to communicate with the client, we use the socket that we received as a result of the accept method. In an infinite loop, we receive 1024 bytes of data using the recv method. If there is no more data, then this method returns nothing. Thus, we can receive any amount of data from the client.
Further in our example, for clarity, we will do something with the received data and send them back to the client. For example, using the upper method on strings, we return a string to the client in uppercase.
Now you can close the connection:
conn.close()
Actually the server is ready. It accepts the connection, accepts data from the client, returns it as a string in upper case, and closes the connection. It's simple :) In the end, you should have the following:
Customer
I think it will be easier now. And the client application itself is simpler - we need to create a socket, connect to the server, send data to it, accept data and close the connection. All this is done like this:
I think that everything is clear, because everything has already been analyzed before. The only new thing here is the connect method, with which we connect to the server. Next we read 1024 bytes of data and close the socket.