I have a command line Python program ... I think an optional web page would be convenient interface. The Python program would listen on some port, and if queried (by me browsing to localhost:12345 for example) would return a pretty status display. Hitting reload would update the status etc.
My problem is that I'm not sure how to do this:
- I don't want to embed a full web server into the application or
require any special PC setup.
- I think I know how to listen on a socket, but not sure how to send
stuff to to a web browser -- just start with <HTML>?
See below. I don't care if you use the code, it was fun to whip up on the spur of the moment. I'm quite certain that if you try searching for "smallest web server" or something you'll find a bunch of Perl guys who've competed to produce something that does the same in a tenth the space...
- Do I need a separate thread to listen and send the HTML? The application is currently single threaded. I'm confortable with threads, but would prefer to avoid them if possible.
If you don't want a thread, you probably don't need one, but this might be a little cleaner to put in a thread. I'm not sure exactly what approach would be best to avoid a thread, but using select() on the server socket, with a timeout of 0 to poll, instead of blocking as the following code does, would probably be the simplest.
Try this out and maybe you can morph it into something like what you want...
'''miniweb: microscopic web server'''
import socket from select import select from datetime import datetime
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('', 80)) s.listen(5) while True: cs = s.accept()[0] try: header = '' while True: r, w, e = select([cs], [], [cs], 2) if not r or e: break
header += cs.recv(1024) if '\r\n\r\n' in header: break
msg = ('<html><head><title>Miniweb!</title></head>'
'<body><h3>Clock</h3><p>The time is %s</p></body></html>' % datetime.now())
headers = '\r\n'.join([ 'HTTP/1.0 200 OK', 'Server: Miniweb-0.1', 'Content-Type: text/html', 'Connection: close', 'Content-Length: %s' % len(msg), ])
cs.send(headers + '\r\n\r\n' + msg + '\n')
finally: cs.close()
I make no claims that this will survive any particular kind of use or abuse. I did test with telnet, Firefox, Opera, and Explorer, however. A couple of key points found while testing:
1. Explorer needs you to read the header in its entirety, so I had to add the part that actually scans the header for the terminating sequence (\r\n\r\n).
2. There's a two-second timeout on reading the header, in case something connects but doesn't send anything... not really tested.
3. Some or most of the headers in the reply may not be required. Perhaps the first line and the Content-Length (or not even that?) are all that are required. Play if you want. No doubt others will pick this apart and we'll all learn something. ;-)
4. MIT license ;-) as in don't complain to me if this doesn't do what you need, but use it any way you wish...
-Peter -- http://mail.python.org/mailman/listinfo/python-list