A tiny python web server for the Raspberry Pi

At the Saturday Pi club, James and I often sit down with the kids and ask them what they are interested in, and try to steer them to explore things that match their interests. The theory is, they will enjoy working on things they are interested in, and they will learn more as part of that journey.

One of the lads said he wanted to build a server. “What kind of server?” I said… “Ah, a web server, that I can store files on and log into across the internet with my Pi plugged into my router at home”.

Now, here is the predicament. Getting a web server running on the Pi is bound to be pretty easy, probably just download apache with apt, and then restart your Pi. That gets you to the end goal pretty quickly, but have you learnt anything in the process? I’m becoming increasingly wary of step by step instructions that kids follow to get to some goal, but then don’t really learn anything as a result. I call this “follow the leader” instructions – you follow ¬†almost blindly some detailed instructions that someone else has spent hours working out, and they either work, or they don’t work. If they work, you have something functional but probably didn’t learn much. If they don’t work, you probably spend the rest of the day trying to get it to work, get very frustrated, learn lots in the process, but are at risk of wiping out a few weeks getting nothing done.

In this case, I wanted to find some half way house where there was an instant learning opportunity. I’ve written some tiny embedded web servers before, and I know that the HTTP protocol in it’s basic form is very very simple. This, and other protocols, are described in the excellent book in reference [1] below.

I decided in this case to give a little recipe to the lad, pre coded, and then let him extend that. Enter stage left, the 13 line python web server…

import SocketServer

class MyTCPHandler(SocketServer.BaseRequestHandler):
	def handle(self):
		self.reqdata = self.request.recv(1024).strip()
		print "{} wrote:".format(self.client_address[0])
		print self.reqdata
		self.send('webserver ONLINE')

	def send(self, content):
		self.request.sendall('HTTP/1.0 200 OK\n\n{}'.format(content))

if __name__ == "__main__":
	HOST, PORT = "0.0.0.0", 9997
	server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
	server.serve_forever()

Ok, so it’s only 13 lines if you ignore the blank ones, but that’s fine, SLOC (source lines of code) is a standard metric that ignores any non-active lines, so I’m not really lying, am I?

This code was pretty much inspired by the online python documentation for the SocketServer class in reference [2], with a few lines added.

It’s a complete multi-threaded server, listening on port 9997, and regardless of what you request from the browser, it always returns a simple page that says “webserver ONLINE”.

Learning Opportunities

We got a huge amount of mileage out of this little 13 line program. First, we had to get the networking set up so that my laptop and the Pi were on the same network – that’s easy now we have the router, but in the early days, we were using cables and static IP so it was a bit more fiddly.

Next, we opened 192.168.1.2 (the IP address of the Pi) in the browser window of the laptop, and magically the page “webserver ONLINE” came back. Some edits of the python and other pages came back.

Here was the real magic bit though – talking through how simple the protocol is that holds up the whole of the world wide web. We opened a telnet program from the laptop like this:

telnet 192.168.1.2 9992

And then typed this:

GET / HTTP/1.0

Note there were two presses of the return key at the end, that is important.

What came back was:

HTTP/1.0 200 OK

webserver ONLINE
connection closed

And, that’s it! That’s how simple the whole of the world wide web is. Total shock on the faces of everyone watching – “what? That’s it? It’s that simple?”

Actually, that’s the simplest possible web server. It doesn’t do anything useful, it doesn’t support attachments and media types, it doesn’t support security, and all the other hundreds of things in the HTTP specification. But yes, it’s basically that simple.

This simple 13 line program and this 2 line demonstration then allowed us to talk about protocols, messages, IP addresses, TCP sockets, well known ports, standards, media types, security, and other countless features that are required to turn this into a “real” web server.

We have since extended the web server to allow it to serve out files from the Pi filing system (it’s still only about a page of python code), and we’re looking at extending it further so that it will run external python scripts written by other kids – one such project discussed was to link this with the work of another team who are building an electronic Dice game using python and some LEDs, with a view to making a web controlled LED dice game.

If you want the extended version of the code, catch me on twitter @whaleygeek

References

[1] TCP/IP Application Layer Protocols for Embedded Systems, by M. Tim Jones

[2] lib/SocketServer.py documentation

 

 

This entry was posted in Older Stuff. Bookmark the permalink.

Comments are closed.