Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A simple WebSockets server with no dependencies
import struct
import SocketServer
from base64 import b64encode
from hashlib import sha1
from mimetools import Message
from StringIO import StringIO
class WebSocketsHandler(SocketServer.StreamRequestHandler):
magic = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
def setup(self):
SocketServer.StreamRequestHandler.setup(self)
print "connection established", self.client_address
self.handshake_done = False
def handle(self):
while True:
if not self.handshake_done:
self.handshake()
else:
self.read_next_message()
def read_next_message(self):
length = ord(self.rfile.read(2)[1]) & 127
if length == 126:
length = struct.unpack(">H", self.rfile.read(2))[0]
elif length == 127:
length = struct.unpack(">Q", self.rfile.read(8))[0]
masks = [ord(byte) for byte in self.rfile.read(4)]
decoded = ""
for char in self.rfile.read(length):
decoded += chr(ord(char) ^ masks[len(decoded) % 4])
self.on_message(decoded)
def send_message(self, message):
self.request.send(chr(129))
length = len(message)
if length <= 125:
self.request.send(chr(length))
elif length >= 126 and length <= 65535:
self.request.send(126)
self.request.send(struct.pack(">H", length))
else:
self.request.send(127)
self.request.send(struct.pack(">Q", length))
self.request.send(message)
def handshake(self):
data = self.request.recv(1024).strip()
headers = Message(StringIO(data.split('\r\n', 1)[1]))
if headers.get("Upgrade", None) != "websocket":
return
print 'Handshaking...'
key = headers['Sec-WebSocket-Key']
digest = b64encode(sha1(key + self.magic).hexdigest().decode('hex'))
response = 'HTTP/1.1 101 Switching Protocols\r\n'
response += 'Upgrade: websocket\r\n'
response += 'Connection: Upgrade\r\n'
response += 'Sec-WebSocket-Accept: %s\r\n\r\n' % digest
self.handshake_done = self.request.send(response)
def on_message(self, message):
print messsage
if __name__ == "__main__":
server = SocketServer.TCPServer(
("localhost", 9999), WebSocketsHandler)
server.serve_forever()
@jkp

This comment has been minimized.

Copy link
Owner Author

jkp commented Jul 18, 2012

Try it out with something like this (http://jsfiddle.net/ is handy for quick tests...):

var ws = new WebSocket("ws://localhost:9999/");
ws.onopen = function() {
    function schedule(i) {
        setTimeout(function() { 
          ws.send('Hello from the client! (iteration ' + i + ')');
          schedule(i + 1);
        }, 1000);            
    };
    schedule(1);            
};
@Mause

This comment has been minimized.

Copy link

Mause commented Aug 28, 2012

I'm working on something using this as the websocket backend and the Webkit notification API :D
https://github.com/Mause/websocket-notifications/

@ghost

This comment has been minimized.

Copy link

ghost commented Nov 4, 2012

You have a typo in your on_message method; you've got the letter S three times on line 63

def on_message(self, message):
print messsage # typo

@baxissimo

This comment has been minimized.

Copy link

baxissimo commented Feb 15, 2013

You should change the serve_forever() part to something like this:
try:
server.serve_forever()
except KeyboardInterrupt:
print "Got ^C"
server.server_close();
print "bye!"

@1tylermitchell

This comment has been minimized.

Copy link

1tylermitchell commented Aug 12, 2013

Awesome, thanks for sharing!

@ImageAsInput

This comment has been minimized.

Copy link

ImageAsInput commented Aug 14, 2013

I am facing a weird problem. Only one client can be connected to this server. Am I missing something really basic ?

@dzava

This comment has been minimized.

Copy link

dzava commented Aug 24, 2013

@Applterate Check this for multiple client support.

@Sepero

This comment has been minimized.

Copy link

Sepero commented Nov 4, 2013

Very impressive. I am happy to be a witness to the excellence of this code.

@alexwahl

This comment has been minimized.

Copy link

alexwahl commented Nov 22, 2013

im trying to use this with python3.. struggling with mimetools.Message can somebody give me a hint how to replace correct with the email package?

@cobainmo

This comment has been minimized.

Copy link

cobainmo commented Dec 13, 2013

I'm totally noob with python and need to make something fast so pelase can you help me. How can i create instance of this class and use send_message() method from external file ?

@AlanBell

This comment has been minimized.

Copy link

AlanBell commented May 1, 2014

self.request.send(126) should be self.request.send(chr(126)), same for 127.

@fredrikhl

This comment has been minimized.

Copy link

fredrikhl commented Aug 26, 2014

You have a typo on line 63:

  def on_message(self, message):
-     print messsage
+     print message
@SevenW

This comment has been minimized.

Copy link

SevenW commented Sep 25, 2014

Thanks for this nice example, which inspired (as in reuse some code) to make a combined HTTP/WebSocket server using one and the same port. The HTTP server part is based on the standard SimpleHTTPServer library.

See https://gist.github.com/SevenW/47be2f9ab74cac26bf21
and for more background:
http://www.sevenwatt.com/main/websocket-html-webserver-python/ for some background

@mbirtwell

This comment has been minimized.

Copy link

mbirtwell commented Mar 14, 2015

Thank you @jkp that was very helpful. I've taken it one step further than @SevenW and turned it in to an git repository (https://github.com/mbirtwell/simple-websockets). I've got examples there of getting this to work with SimpleHTTPServer, wsgiref and werkzeug.

@SevenW

This comment has been minimized.

Copy link

SevenW commented May 25, 2015

I have added support for SSL/HTTPS, and added exception handling. I updated my gist,
https://gist.github.com/SevenW/47be2f9ab74cac26bf21
and also created a repository for further maintenance:
https://github.com/SevenW/httpwebsockethandler

An elaborate example for the web interface for Plugwise-2-py can be found here:
https://github.com/SevenW/Plugwise-2-py

@nevinvalsaraj

This comment has been minimized.

Copy link

nevinvalsaraj commented Jul 2, 2015

Thanks @jkp, that's lightweight and serves most development purposes. I recommend adding

SocketServer.TCPServer.allow_reuse_address = True

to set SO_REUSEADDR socket option before TCPServer instantiation on line 66 in case the script is run repeatedly during development.

@miloszw

This comment has been minimized.

Copy link

miloszw commented Jul 8, 2015

Here is a somewhat more modular version if anyone wants to use this as an import.

@crossmax

This comment has been minimized.

Copy link

crossmax commented Jan 12, 2016

Hi, I trying launch the web socket server with param secure and I get this error:

File "main.py", line 50, in _ws_main
    server.socket = ssl.wrap_socket (server.socket, certfile='./server.pem', server_side=True)
File "/usr/lib/python2.7/ssl.py", line 891, in wrap_socket
    ciphers=ciphers)
File "/usr/lib/python2.7/ssl.py", line 509, in __init__
    self._context.load_cert_chain(certfile, keyfile)
ssl.SSLError: [SSL] PEM lib (_ssl.c:2525)

I read that this error is caused for a bad private key, but I've added it as a parameter in the function wrap_socket() and result is the same. My cert and key are self-signed, I created it with openssl command.
How I can resolve this?

Thanks in advance

@abs1001

This comment has been minimized.

Copy link

abs1001 commented Oct 13, 2017

i need to send binary data over this server. will it work ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.