SoFunction
Updated on 2024-10-30

Detailed explanation of Python Socket network programming

Socket is a way of inter-process communication, it and other inter-process communication is a major difference: it can realize the inter-process communication between different hosts, most of the various services on our network are based on sockets to complete the communication, such as we browse the web every day, QQ chat, send and receive emails and so on. To solve the problem of process communication between two hosts on the network, we must first uniquely identify the process, in the TCP/IP network protocol, is through the (IP address, protocol, port number) ternary to identify the process, to solve the problem of process identification, there is a basis for communication.

This article focuses on TCP socket network programming using Python, assuming that you already have a preliminary knowledge of networking and basic syntax knowledge of Python.

TCP is a connection-oriented transport layer protocol, TCP Socket is based on a Client-Server programming model, the server side listens to the client's connection request, once the connection is established to transfer data. So the introduction of TCP socket programming is also divided into client-side and server-side:

I. Client Programming
Creating a socket

The first step is to create a socket, which you can do with socket, a function of the socket module in Python:

#Socket client example in python
 
import socket  #for sockets
 
#create an AF_INET, STREAM socket (TCP)
s = (socket.AF_INET, socket.SOCK_STREAM)
 
print 'Socket Created'

function creates a socket and returns the descriptor of the socket, which will be used later in the related functions. The function takes two arguments:

Address Family: either AF_INET (for Internet inter-process communication) or AF_UNIX (for inter-process communication on the same machine).
Type: socket type, can be SOCKET_STREAM (streaming socket, mainly used for TCP protocol) or SOCKET_DGRAM (datagram socket, mainly used for UDP protocol)
Note: Because this article is mainly an overview of the process of Python Socket Programming, so will not be related to the function parameters, return values for a detailed introduction, you need to understand the relevant manuals can be viewed!

error handling

If the socket creation function fails, an exception is thrown that needs to be caught:

#handling errors in python socket programs
 
import socket  #for sockets
import sys #for exit
 
try:
  #create an AF_INET, STREAM socket (TCP)
  s = (socket.AF_INET, socket.SOCK_STREAM)
except , msg:
  print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
  ();
 
print 'Socket Created'

So we've created a socket so far, and we're going to use it to connect to a server, so let's do that.

Connecting to the server

As mentioned at the beginning of this article, sockets use (IP address, protocol, port number) to identify a process, so in order to communicate with the server, we need to know its IP address and port number.

Obtain the IP address of the remote host

Python provides a simple function to get the IP address of a remote host:

host = ''
port = 80
 
try:
  remote_ip = ( host )
 
except :
  #could not resolve
  print 'Hostname could not be resolved. Exiting'
  ()
   
print 'Ip address of ' + host + ' is ' + remote_ip

Now that we know the IP address of the server, we can use the connect function to connect to a specific port on that IP. The following example connects to port 80 (which is the default port for HTTP services):

#Connect to remote server
((remote_ip , port))
 
print 'Socket Connected to ' + host + ' on ip ' + remote_ip

Run the program:

$ python 
Socket created
Ip of remote host  is 173.194.38.145
Socket Connected to  on ip 173.194.38.145

Send data

The above shows that the connection has been successful, then we can send some data to the server, such as sending the string GET / HTTP/1.1\r\n\r\n, which is an HTTP request for web page content command.

#Send some data to remote server
message = "GET / HTTP/1.1\r\n\r\n"
 
try :
  #Set the whole string
  (message)
except :
  #Send failed
  print 'Send failed'
  ()
 
print 'Message send successfully'

After sending the data, the client also needs to receive a response from the server.

receive data

The recv function can be used to receive data from a socket:

#Now receive data
reply = (4096)
 
print reply

The results of running them together are as follows:

Socket created
Ip of remote host  is 173.194.38.145
Socket Connected to  on ip 173.194.38.145
Message send successfully
HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Location: /?gfe_rd=cr&ei=PlqJVLCREovW8gfF0oG4CQ
Content-Length: 262
Date: Thu, 11 Dec 2014 08:47:58 GMT
Server: GFE/2.0
Alternate-Protocol: 80:quic,p=0.02

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="/?gfe_rd=cr&ei=PlqJVLCREovW8gfF0oG4CQ">here</A>.
</BODY></HTML>

Close socket

When we don't want to request data from the server again, we can close the socket and end the communication:

()
wrap-up

Above we learned how:

  • Creating a socket
  • Connecting to a Remote Server
  • Send data
  • receive data
  • Close socket

When we open the It makes sense to know that this is what the browser does when it comes to sockets. A socket with this behavior is called a CLIENT, and the client mainly connects to the remote system to get data.

The other behavior in socket is called SERVER. The server uses socket to receive connections and provide data, which is the opposite of the client. So it's the server and your browser is the client, or more accurately, it's the HTTP server and your browser is the HTTP client.

So we've covered client-side programming, now it's the server's turn to use sockets.

II. Server-side programming
The server side does the following:

  • Open socket
  • Bind to a specific address and port
  • monitor a connection
  • establish a connection
  • Receive/Send Data

Now that you've seen how to create a socket, the next step is to bind it.

Binding sockets

The bind function can be used to bind a socket to a specific address and port, and takes a sockaddr_in structure as an argument:

import socket
import sys
 
HOST = ''  # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
 
s = (socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
try:
  ((HOST, PORT))
except  , msg:
  print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
  ()
   
print 'Socket bind complete'

Once the binding is complete, the next step is to listen for connections.

monitor a connection

The listen function puts the socket in listen mode:

(10)
print 'Socket now listening'

This function takes a parameter called backlog, which controls the number of connections. If it is set to 10, then there are 10 connections waiting to be processed and the 11th request will be rejected.

receiver connection

When a client sends a connection request to the server, the server receives the connection:

#wait to accept a connection - blocking call
conn, addr = ()
 
#display client information
print 'Connected with ' + addr[0] + ':' + str(addr[1])

of running the program, the output is as follows:

$ python 
Socket created
Socket bind complete
Socket now listening

At this point, the program is waiting for a request to come in on port 8888. Don't close the program, leave it running, and the client can now connect to the socket on that port. let's test this with a telnet client by opening a terminal and typing telnet localhost 8888:

$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

This is what the server-side output will show:

$ python 
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:59954

We observe that the client has connected to the server. After establishing the connection, we can use it to communicate with the client. The following example demonstrates that after the server establishes the connection, it receives the data sent by the client and immediately sends the data back, below is the complete server side program:

import socket
import sys
 
HOST = ''  # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
 
s = (socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
try:
  ((HOST, PORT))
except  , msg:
  print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
  ()
   
print 'Socket bind complete'
 
(10)
print 'Socket now listening'
 
#wait to accept a connection - blocking call
conn, addr = ()
 
print 'Connected with ' + addr[0] + ':' + str(addr[1])
 
#now keep talking with the client
data = (1024)
(data)
 
()
()

Run this program in one terminal, open another terminal, use telnet to connect to the server, type in a random string and you'll see:

$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
happy
happy
Connection closed by foreign host.

The client (telnet) receives a response from the server.

The server disconnects as soon as we finish a response, and servers like this are always waiting to receive connections. The easiest way to make the above server program run all the time is to put accept into a loop, and it will always receive connections.

Maintenance services

We can change the code to make the server work all the time like this:

import socket
import sys
 
HOST = ''  # Symbolic name meaning all available interfaces
PORT = 5000 # Arbitrary non-privileged port
 
s = (socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
try:
  ((HOST, PORT))
except  , msg:
  print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
  ()
   
print 'Socket bind complete'
 
(10)
print 'Socket now listening'
 
#now keep talking with the client
while 1:
  #wait to accept a connection - blocking call
  conn, addr = ()
  print 'Connected with ' + addr[0] + ':' + str(addr[1])
   
  data = (1024)
  reply = 'OK...' + data
  if not data: 
    break
   
  (reply)
 
()
()

Now run the above server program in a terminal, and then open three terminals, respectively, with telnet to connect, if a terminal is connected to the other terminals without inputting data there is no way to connect, and each terminal can only be serviced once before disconnecting. This can also be seen from the code.

This is obviously not what we want, we want multiple clients to be able to establish a connection at any time, and each client can communicate with the server multiple times, how can this be modified?

process a connection

To handle each connection, we need to separate the program that handles it from the main program that receives the connection. One way to do this could be to use threads, where the main service program receives the connection, creates a thread to handle the communication for that connection, and then the server goes back to the logic of receiving the other connections.

import socket
import sys
from thread import *
 
HOST = ''  # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
 
s = (socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
#Bind socket to local host and port
try:
  ((HOST, PORT))
except  , msg:
  print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
  ()
   
print 'Socket bind complete'
 
#Start listening on socket
(10)
print 'Socket now listening'
 
#Function for handling connections. This will be used to create threads
def clientthread(conn):
  #Sending message to connected client
  ('Welcome to the server. Type something and hit enter\n') #send only takes string
   
  #infinite loop so that function do not terminate and thread do not end.
  while True:
     
    #Receiving from client
    data = (1024)
    reply = 'OK...' + data
    if not data: 
      break
   
    (reply)
   
  #came out of loop
  ()
 
#now keep talking with the client
while 1:
  #wait to accept a connection - blocking call
  conn, addr = ()
  print 'Connected with ' + addr[0] + ':' + str(addr[1])
   
  #start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
  start_new_thread(clientthread ,(conn,))
 
()

Run the above program again and open three terminals to establish a telnet connection with the master server. At this time, the three clients can be accessed at any time, and each client can communicate with the master server several times.

The following output is possible in a telnet terminal:

$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Welcome to the server. Type something and hit enter
hi
OK...hi
asd
OK...asd
cv
OK...cv

To end the telnet connection, press the Ctrl-] key and enter the close command.

The output from the server terminal might look like this:

$ python 
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:60730
Connected with 127.0.0.1:60731

So far, we've learned the basics of socket programming in Python, and there's more to come, so don't go away.