Skip to content

Instantly share code, notes, and snippets.

@jkp
Created July 18, 2012 13:28
Show Gist options
  • Save jkp/3136208 to your computer and use it in GitHub Desktop.
Save jkp/3136208 to your computer and use it in GitHub Desktop.
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()
@crossmax
Copy link

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
Copy link

abs1001 commented Oct 13, 2017

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

@npkq
Copy link

npkq commented Nov 25, 2022

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

To handle multiple client support:

At the beginning of the websocketserver-py file: I added:
import sys ###
import threading ###
from SocketServer import ThreadingMixIn ###

At the end of the websocketserver-py file: I added a class ThreadedWebSocketServer and adapted the 'if name == "main" ' part.

class ThreadedWebSocketServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
"""Handle requests in a separate thread."""
# Ctrl-C will cleanly kill all spawned threads
daemon_threads = True
# much faster rebinding
allow_reuse_address = True

def __init__(self, server_address, RequestHandlerClass):
    SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)

if name == "main":
##server = SocketServer.TCPServer(
## ("127.0.0.1", 8088), WebSocketsHandler)
server = ThreadedWebSocketServer(("127.0.0.1", 8088), WebSocketsHandler) ###
# terminate with Ctrl-C
try:
server.serve_forever()
except KeyboardInterrupt:
print ('========================================')
print ('^C received, shutting down server')
print ('========================================')
server.socket.close()
sys.exit(0)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment