CrazyTB's blog

Simple TCP server written in Python, using socket and select

,

Today I started writing a small server using TCP sockets in Python. Nothing very big, nothing very special, and still far from finished, but I thought I should share the code I have now. Currently, I have an uber-simple server that listens to a TCP port and can accept multiple connections (IPv4 only). All running in a single thread and using only 20 lines of Python code.

Introduction

I'm supposing you know Python somewhat well, and know how TCP/IP works. No need to be an expert, but a good understanding of how it works helps a lot. For testing, a telnet or netcat client is handy.

Before writing the code below, I read these pages:

How it works

At first, the server will create a socket object to bind itself to a port on local machine, accepting connections from any IP. This socket can only be used to listen for new connections; no data is sent or received through this socket.

Then the server enters an infinite loop, using select() to wait for I/O.

When a new connection is received, the .accept() method will return a new socket object that is specific for this new connection. This new socket can be used for sending and receiving data, while the old listening socket is kept intact. This new socket is added to a list of currently open sockets.

When data is received from an open socket, the data is read using .recv() and then printed to the server terminal. If .recv() returns no data (empty string), it means that the connection was closed (unfortunately, this is not described at Python documentation, but it is described at recv(2) man page).

No exception handling is done. Actually, right now I don't even know if this code can generate exceptions. (information regarding this is very appreciated)

The code

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import socket, select

# List of socket objects that are currently open
open_sockets = []

# AF_INET means IPv4.
# SOCK_STREAM means a TCP connection.
# SOCK_DGRAM would mean an UDP "connection".
listening_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )

# The parameter is (host, port).
# The host, when empty or when 0.0.0.0, means to accept connections for
# all IP addresses of current machine. Otherwise, the socket will bind
# itself only to one IP.
# The port must greater than 1023 if you plan running this script as a
# normal user. Ports below 1024 require root privileges.
listening_socket.bind( ("", 1234) )

# The parameter defines how many new connections can wait in queue.
# Note that this is NOT the number of open connections (which has no limit).
# Read listen(2) man page for more information.
listening_socket.listen(5)


while True:
    # Waits for I/O being available for reading from any socket object.
    rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
    for i in rlist:
        if i is listening_socket:
            new_socket, addr = listening_socket.accept()
            open_sockets.append(new_socket)
        else:
            data = i.recv(1024)
            if data == "":
                open_sockets.remove(i)
                print "Connection closed"
            else:
                print repr(data)

Testing

You can write a Python client to test this server, you can just use netcat. Run the following command at your shell:
nc 127.0.0.1 1234
Then type something and press Enter. To close the netcat, press Ctrl-C.

Try opening multiple simultaneous connections, and also from different hosts, just to see that things actually work, even with such simple code.

And that's all, folks! I hope this code is useful for someone else, as it shows how select() and sockets can be combined. Have fun!

Comparison of Java equality comparisonRunning md5sum on Nokia phone using Python S60

Comments

Mad Scientistqlue Wednesday, February 11, 2009 4:36:16 PM

I want to get back into programming but I've no idea where to start. My limited background is the seriously obsolete Commodore 64 which taught me BASIC and 6502 machine code. I also did a COBAL course many moons ago but I can't recall much of that. I'll need to buy hardware, software and some books to get started. I don't have any sort of computer at all yet. (I use my mobile to in online.) I'd particularly like to get involved in programming for mobile devices. Can you give me some idea of what to do to get started?

Unregistered user Wednesday, August 19, 2009 11:07:17 AM

Rajkumar writes: I'm new to phython and currently working with asp.net. Can i use this code to open a socket at the client side of my web application keep the port open until he shuts the window. Can we categorize phython into a client server architecture? If phython can be used to open a socket and we can keep communicating to it from any remote location or an asp.net application then it would be a great thing as it will improve the performance of the server by keeping the number of requests to be low cause all the current asp.net chat applications need to post back to the server every 2 seconds to check whether there is any message for him or not. if there is some solution or you couldn't get what am i saying please mail me at koolraj@gmail.com

Denilson Figueiredo de SáCrazyTerabyte Thursday, August 20, 2009 12:06:35 AM

Rajkumar,

If you are working with web applications (that should run inside a web browser), you should (I mean... you MUST) stick to JavaScript for the client-side.

Thus, by your description it seems you want this:
http://en.wikipedia.org/wiki/Comet_(programming)

Sorry, I can't help you more than this.

Unregistered user Thursday, August 20, 2009 10:01:13 AM

Rajkumar writes: Thanks for letting me know.

Unregistered user Tuesday, July 6, 2010 1:36:38 PM

Guilherme Chapiewski writes: I'm going to start writing a simple TCP server in Python today and curiously Google redirected me to your blog :) :) :) I wonder if you have any new thoughts/updates on this code, specially about performance/limits of this implementation. Thanks! Cheers, gc

Denilson Figueiredo de SáCrazyTerabyte Tuesday, July 6, 2010 2:38:30 PM

hehe! bigsmile Small (Internet) world, huh? p

No, I did no modifications to that code. I wrote that as a simple "proof-of-concept", and haven't improved nor stress-tested it.

If you have improvements, comments, or anything else, please feel free to post at your blog or at your github (or bitbucket), and I'll add a link here. smile

Unregistered user Tuesday, July 6, 2010 7:55:12 PM

Guilherme Chapiewski writes: Sweet :) Thanks!

Unregistered user Thursday, June 23, 2011 9:47:52 AM

Neil writes: Hi, Thanks for the great post. It's exactly what I wanted to find when I went to Google! A very simple improvement to the code is to add a try, except block to let the server keep running when a client forcibly closes the connection (e.g. with ctrl-c). I added this instead of the line: data = i.recv(1024) --- try: data = i.recv(1024) except: data = "" print "There was an exception" --- That will allow it to go back and wait for the next connection.

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies

May 2012
S M T W T F S
April 2012June 2012
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31