Python network sockets programming tutorial

In this tutorial you will learn about in network programming. You will learn about the client-server model that is in use for the World Wide Web, E-mail and many other applications.

client server
Client server (with email protocol)
The client server model is a model where there are n clients and one server. The clients make  data requests to a server. The server replies to those messages received. A client can be any device such as  your computer or tablet. Servers are generally dedicated computers which are to be connected 24/7

Related course:
If you prefer a course or certification:

socket server code

This code will start a simple web server using sockets. It waits for a connection and if a connection is received it will output the bytes received.

#!/usr/bin/env python
 
import socket
 
TCP_IP = '127.0.0.1'
TCP_PORT = 62
BUFFER_SIZE = 20  # Normally 1024, but we want fast response
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
 
conn, addr = s.accept()
print 'Connection address:', addr
while 1:
     data = conn.recv(BUFFER_SIZE)
     if not data: break
     print "received data:", data
     conn.send(data)  # echo
conn.close()

Execute with:

$ python server.py

This opens the web server at port 62. In a second screen, open a client with Telnet. If you use the same machine for the client and server use:

$ telnet 127.0.0.1 62.

If you use another machine as client, type the according IP address of that machine. You can find it with ifconfig.

Everything you write from the client will arrive at the server. The server sends the received messages back. An example output below (Click to enlarge):

socket network client:

The client script below sends a message to the server. The server must be running!

#!/usr/bin/env python
 
import socket
 
 
TCP_IP = '127.0.0.1'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!"
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
 
print "received data:", data

This client simply mimics the behavior we did in Telnet.

Limitations of the server code
The server code above can only interact with one client.  If you try to connect with a second terminal it simply won’t reply to the new client. To let the server interact with multiple clients you need to use multi-threading. We rebuild the server script to accept multiple client connections:

#!/usr/bin/env python
 
import socket
from threading import Thread
from SocketServer import ThreadingMixIn
 
class ClientThread(Thread):
 
    def __init__(self,ip,port):
        Thread.__init__(self)
        self.ip = ip
        self.port = port
        print "[+] New thread started for "+ip+":"+str(port)
 
 
    def run(self):
        while True:
            data = conn.recv(2048)
            if not data: break
            print "received data:", data
            conn.send(data)  # echo
 
TCP_IP = '0.0.0.0'
TCP_PORT = 62
BUFFER_SIZE = 20  # Normally 1024, but we want fast response
 
 
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind((TCP_IP, TCP_PORT))
threads = []
 
while True:
    tcpsock.listen(4)
    print "Waiting for incoming connections..."
    (conn, (ip,port)) = tcpsock.accept()
    newthread = ClientThread(ip,port)
    newthread.start()
    threads.append(newthread)
 
for t in threads:
    t.join()

Application protocol

So far we have simply sent messages back and forth. Every message can have a specific meaning in an application. This is known as the protocol.  The meaning of these messages must be the same on both the sender and receiver side.  The Transport Layer below makes sure that messages are received (TCP). The Internet Layer is the IPv4 protocol.  All we have to define is the Application Layer.

Below we modified the server to accept simple commands (We use the non-threading server for simplicity). We changed the port to 64.  Server code with a protocol:

#!/usr/bin/env python
 
import socket
 
TCP_IP = '127.0.0.1'
TCP_PORT = 64
BUFFER_SIZE = 20  # Normally 1024, but we want fast response
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
 
conn, addr = s.accept()
print 'Connection address:', addr
while 1:
     data = conn.recv(BUFFER_SIZE)
     if not data: break
     print "received data:", data
     #conn.send(data)  # echo
     if "/version" in data:
         conn.send("Demo versionn")
 
     if "/echo" in data:
         data = data.replace("/echo","")
         conn.send(data + "n")
 
conn.close()

Run the server with:

sudo python server.py

A client can then connect with telnet (make sure you pick the right IP):

$ telnet 127.0.0.1 64
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
message
/version
Demo version
/echo Repeat this
 Repeat this

Download sockets Code

Building an IRC (ro)bot

There are tons of (ro)bots out there for IRC (Internet Relay Chat). So how do you start and build one in Python, just for fun?

You will need a program that connects with an IRC server and acts like a traditional IRC client.  IRC servers never ask for any type of complicated human verification such as solving captchas, which is why we can simply connect with a script. The script itself will use network sockets,  a library that is often used to provide network interactions in many programming languages including Python and C/C++.

Related course
Mastering Python – Networking and Security

IRC and Python
To communicate with an IRC server, you need to use the IRC protocol.  The IRC protocol has distinct messages such as PRIVMSG, USER, NICK and JOIN. If you are curious, you could read the entire protocol. But following this tutorial may be a lot simpler 😉 Authentication is achieved using only a few steps:

The IRC protocol is a layer on top of the IP protocol.   To create a socket we use the command:

 irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

socket.AF_INET tells the library to use the network protocol IPv4.   The second argument tells the library to use stream sockets, which are traditionally implemented on the TCP protocol. (IRC works over TCP/IP). We then must use the commands to authenticate with the server:

USER botname botname botname: phrase
NICK botname
JOIN #channel

Sometimes the IDENT command is neccesary too. Summing up, we get this class (save it as irc.py):

import socket
import sys
 
 
class IRC:
 
    irc = socket.socket()
  
    def __init__(self):  
        self.irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
    def send(self, chan, msg):
        self.irc.send("PRIVMSG " + chan + " " + msg + "n")
 
    def connect(self, server, channel, botnick):
        #defines the socket
        print "connecting to:"+server
        self.irc.connect((server, 6667))                                                         #connects to the server
        self.irc.send("USER " + botnick + " " + botnick +" " + botnick + " :This is a fun bot!n") #user authentication
        self.irc.send("NICK " + botnick + "n")               
        self.irc.send("JOIN " + channel + "n")        #join the chan
 
    def get_text(self):
        text=self.irc.recv(2040)  #receive the text
 
        if text.find('PING') != -1:                      
            self.irc.send('PONG ' + text.split() [1] + 'rn') 
 
        return text

Now that we have the network connectivity class, we can use it as an instance.  We will keep our (ro)bot simple for explanatory purposes. The bot will reply “Hello!” if it gets the message “hello” in the channel it resides.

from irc import *
import os
import random
 
channel = "#testit"
server = "irc.freenode.net"
nickname = "reddity"
 
irc = IRC()
irc.connect(server, channel, nickname)
 
 
while 1:
    text = irc.get_text()
    print text
 
    if "PRIVMSG" in text and channel in text and "hello" in text:
        irc.send(channel, "Hello!")

Save it as bot.py and run with python bot.py. Connect with a traditional irc client (mirc,hexchat,irsii) to the the channel and observe the experiment has worked! You can now extend it with any cool features you can imagine.