Introduction to Python Socket programming

  • 2020-04-02 13:50:45
  • OfStack

This is a quick tutorial and tutorial for learning Python Socket Socket programming. Python's Socket programming is very similar to the C language.
Python official function of Socket see (link: http://docs.python.org/library/socket.html)
Basically, sockets are the most basic part of any computer network communication. For example, when you type www.jb51.net in the browser address bar, you will open a socket, connect to www.jb51.net, read the page that responded to, and then display it. Other chat clients like gtalk and skype are similar. Any network communication is done through sockets.

Written in the beginning

This tutorial assumes that you already have some basic knowledge of Python programming.
Let's start Socket programming.

Create a Socket

The first thing to do is to create a Socket Socket Socket Socket function can be achieved, the code is as follows:


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

Function socket.socket creates a socket and returns the descriptor of the socket for use by other socket-related functions.
The above code USES the following two properties to create a Socket:
Address cluster: AF_INET (IPv4)
Type: SOCK_STREAM (using TCP transport control protocol)

Error handling

If the socket function fails, python throws an exception called socket.error, which must be handled:


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

Okay, now that you've successfully created a Socket, what should you do next? Next we will use this Socket to connect to the server.

Note:

The other type that corresponds to SOCK_STREAM is SOCK_DGRAM for UDP communication protocol, UDP communication is not a Socket connection, in this article we will only discuss SOCK_STREAM, or TCP.

Connect to server

Connecting to a server requires the server address and port number, which are www.jb51.net and port 80.

First get the IP address of the remote host

Before connecting to a remote host, we need to know its IP address. In Python, getting an IP address is easy:


import socket #for sockets
import sys #for exit try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit(); print 'Socket Created' host = 'www.jb51.net' try:
    remote_ip = socket.gethostbyname( host ) except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()
   
print 'Ip address of ' + host + ' is ' + remote_ip

Now that we have the IP address, we need to specify the port to connect to.
Code:


import socket #for sockets
import sys #for exit try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit(); print 'Socket Created' host = 'www.jb51.net'
port = 80 try:
    remote_ip = socket.gethostbyname( host ) except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()
   
print 'Ip address of ' + host + ' is ' + remote_ip #Connect to remote server
s.connect((remote_ip , port)) print 'Socket Connected to ' + host + ' on ip ' + remote_ip

Now run the program


$ python client.py
Socket Created
Ip address of www.jb51.net is 61.145.122.155
Socket Connected to www.jb51.net on ip 61.145.122.155

This program creates a Socket and connects to it. How about using some other port (such as 81) that doesn't exist? This logic is equivalent to building a port scanner.
The connection is made, and the next step is to send the data to the server.

Helpful hints

Use the SOCK_STREAM/TCP socket to have the concept of a connection. Connectivity means a reliable data flow mechanism that can have multiple data streams at the same time. Think of it as a pipeline of data that doesn't interfere with each other. Another important tip is that packets are sent and received in sequence.
Other sockets such as UDP, ICMP, and ARP don't have the concept of "connections." they are connectionless communications, meaning you can send and receive packets from or to anyone.

To send data

Sendall function is used to simply send data, we send some data to oschina:


import socket #for sockets
import sys #for exit try:
    #create an AF_INET, STREAM socket (TCP)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
    sys.exit(); print 'Socket Created' host = 'www.jb51.net'
port = 80 try:
    remote_ip = socket.gethostbyname( host ) except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit()
   
print 'Ip address of ' + host + ' is ' + remote_ip #Connect to remote server
s.connect((remote_ip , port)) print 'Socket Connected to ' + host + ' on ip ' + remote_ip #Send some data to remote server
message = "GET / HTTP/1.1rnrn" try :
    #Set the whole string
    s.sendall(message)
except socket.error:
    #Send failed
    print 'Send failed'
    sys.exit() print 'Message send successfully'

In the above example, first connect to the target server and then send the string data "GET/HTTP/1.1\r\n\r\n", which is an HTTP protocol command to GET the contents of the homepage of the website.

Next you need to read the data returned by the server.

Receive data

Recv function is used to receive data from socket:


#Socket client example in python import socket #for sockets
import sys #for exit #create an INET, STREAMing socket
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
    print 'Failed to create socket'
    sys.exit()
   
print 'Socket Created' host = 'jb51.net';
port = 80; try:
    remote_ip = socket.gethostbyname( host ) except socket.gaierror:
    #could not resolve
    print 'Hostname could not be resolved. Exiting'
    sys.exit() #Connect to remote server
s.connect((remote_ip , port)) print 'Socket Connected to ' + host + ' on ip ' + remote_ip #Send some data to remote server
message = "GET / HTTP/1.1rnHost: jb51.netrnrn" try :
    #Set the whole string
    s.sendall(message)
except socket.error:
    #Send failed
    print 'Send failed'
    sys.exit() print 'Message send successfully' #Now receive data
reply = s.recv(4096) print reply

The following is the result of the above procedure:


$ python client.py
Socket Created
Ip address of jb51.net is 61.145.122.
Socket Connected to jb51.net on ip 61.145.122.155
Message send successfully
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Wed, 24 Oct 2012 13:26:46 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Keep-Alive: timeout=20
Location: //www.jb51.net/

Jb51.net responds to the content of the URL we requested, simple. After receiving the data, the Socket can be closed.

Close the socket

Close is used to close the Socket:

s.close()

Here it is.

Let's go back

In the above example we learned how to:
1. Create a Socket
Connect to a remote server
3. Send data
4. Receive feedback

The same is true when you use a browser to open www.jb51.net. Contains two types, the client and the server, the client connects to the server and reads the data, and the server receives the incoming connection and provides the data using a Socket. So here www.jb51.net is the server side and your browser is the client side.
Next we'll start to do a little bit of coding on the server side.

Server-side programming

Server-side programming mainly includes the following steps:
1. Open the socket
Bind to an address and port
3. Listen for incoming connections
Accept connections
5. Read and write data
We have learned how to open a Socket, and the following is bound to the specified address and port.

Bind the Socket

The bind function, which binds a Socket to a specific address and port, requires a sockaddr_in structure similar to that required for the connect function.
Sample code:


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

Once the binding is complete, you need to let the Socket start listening for connections. Obviously, you cannot bind two different sockets to the same port.

Connect to listen to

After binding the Socket, we can start listening for connections. We need to turn the Socket into listening mode. Socket's listen function is used to implement the listening mode:


s.listen(10)
print 'Socket now listening'

The parameters required for the listen function become a backlog to control the number of connections that can be kept waiting while the program is busy. Here we pass 10, which means that if there are already 10 connections waiting to be processed, the 11th connection will be rejected. This becomes clearer when you check for socket_accept.

Accept connections
Sample code:


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

The output
Running this program will display:

$ python server.py
Socket created
Socket bind complete
Socket now listening

Now the program is waiting for the connection to enter, port is 8888, please do not close the program, we will test through the Telnet program.
Open a command line window and type:

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

The server-side window displays:
$ python server.py
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:59954

We can see that the client has successfully connected to the server.
In the above example, we receive a connection and close it immediately. Such a program has no real value. There is usually a lot of work to be done after the connection is established, so let's give the client some feedback.
Sendall function can send data to client through Socket:


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

Continue to run the above code, then open another command line window and enter the following command:

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

You can see that the client receives the response content from the server side.
In the above example, the server responds and exits immediately. Some real servers, like www.jb51.net, are always running and accepting connection requests.
That is to say, the server side should be running all the time, otherwise it cannot be a "service", so we need to keep the server side running, the easiest way is to put the accept method in a loop.

The server that has been running

Make a few changes to the above code:


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

It's as simple as adding one more while 1 statement.
Continue running the server, and then open three more command line Windows. Each window connects to the server using the Telnet command:

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

The terminal window where the server is located displays:
$ python server.py
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:60225
Connected with 127.0.0.1:60237
Connected with 127.0.0.1:60239

You see the server never quits again, ok, close the server with Ctrl+C, all Telnet terminals will say "Connection closed by foreign host."
This is fine, but it's inefficient. The server program USES a loop to accept connections and send responses, which is equivalent to processing at most one client request at a time, whereas we require the server to handle multiple requests at once.

Handling multiple connections

To handle multiple connections, we need a separate processing code that runs when the primary server receives the connection. One way is to use threads, where the server receives the connection and creates a thread to process the connection to send and receive data, and then the main server program returns to receive the new connection.
Here's how we use threads to handle connection requests:

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

Run the server program, then open three terminal Windows as before and execute the telent command:

$ 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

The output information of the terminal window where the server is located is as follows:
$ python server.py
Socket created
Socket bind complete
Socket now listening
Connected with 127.0.0.1:60730
Connected with 127.0.0.1:60731

The thread takes over the connection and returns the data to the client.
This is the server-side programming we are going to cover.

conclusion

So far, you've learned the basics of Socket programming in Python, and you can write your own examples to reinforce this knowledge.
You may encounter some problems: Bind failed. Error Code: 98 Message Address already in use, which can be encountered by simply changing the server port.


Related articles: