I am trying to build a websocket server to run on the Raspberry Pi. The websocket server has to push periodic realtime update to a browser. Here is a sample code that I am planning to use. The example code here sends the current time instead of sensor data.
Most of the code is built form an example. However, what I need feedback on is
- The way stpoll is coded (sensor status poll)
- The global variable that passes the message to terminate the thread. I don't like it. Is there a better way to terminate a task that runs forever?
- The way the time (sensor data) is broadcasted to all connected clients. (another global variable)
I had to code this without much documentation.
# -*- coding: utf-8 -*-
import argparse
import random
import os
import time
import threading
import signal
import sys
import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
from ws4py.messaging import TextMessage
class ChatWebSocketHandler(WebSocket):
def received_message(self, m):
cherrypy.engine.publish('websocket-broadcast', m)
def closed(self, code, reason="A client left the room without a proper explanation."):
cherrypy.engine.publish('websocket-broadcast', TextMessage(reason))
class Root(object):
def __init__(self, host, port, ssl=False):
self.host = host
self.port = port
self.scheme = 'wss' if ssl else 'ws'
@cherrypy.expose
def index(self):
return """<html>
<head>
<script type='application/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js'></script>
<script type='application/javascript'>
$(document).ready(function() {
websocket = '%(scheme)s://%(host)s:%(port)s/ws';
if (window.WebSocket) {
ws = new WebSocket(websocket);
}
else if (window.MozWebSocket) {
ws = MozWebSocket(websocket);
}
else {
console.log('WebSocket Not Supported');
return;
}
window.onbeforeunload = function(e) {
$('#chat').val($('#chat').val() + 'Bye bye...\\n');
ws.close(1000, '%(username)s left the room');
if(!e) e = window.event;
e.stopPropagation();
e.preventDefault();
};
ws.onmessage = function (evt) {
$('#chat').val($('#chat').val() + evt.data + '\\n');
};
ws.onopen = function() {
ws.send("%(username)s entered the room");
};
ws.onclose = function(evt) {
$('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n');
};
$('#send').click(function() {
console.log($('#message').val());
ws.send('%(username)s: ' + $('#message').val());
$('#message').val("");
return false;
});
});
</script>
</head>
<body>
<form action='#' id='chatform' method='get'>
<textarea id='chat' cols='35' rows='10'></textarea>
<br />
<label for='message'>%(username)s: </label><input type='text' id='message' />
<input id='send' type='submit' value='Send' />
</form>
</body>
</html>
""" % {'username': "User%d" % random.randint(0, 100), 'host': self.host, 'port': self.port, 'scheme': self.scheme}
@cherrypy.expose
def ws(self):
cherrypy.log("Handler created: %s" % repr(cherrypy.request.ws_handler))
def stpoll(arg):
global pollStatus
while pollStatus:
tm=time.localtime();
print tm.tm_sec
if 'WebSocket' in globals():
print "WS !"
cherrypy.engine.publish('websocket-broadcast', '%s ' %tm)
time.sleep(2)
print "exitting therad"
def signal_handler(signal, frame):
global pollStatus
pollStatus=False
cherrypy.engine.stop()
cherrypy.engine.exit()
print('You pressed Ctrl+C!')
if __name__ == '__main__':
import logging
from ws4py import configure_logger
configure_logger(level=logging.DEBUG)
signal.signal(signal.SIGINT, signal_handler)
pollStatus=True
thread = threading.Thread(target = stpoll, args = (10, ))
thread.daemon = True
thread.start()
parser = argparse.ArgumentParser(description='Echo CherryPy Server')
parser.add_argument('--host', default='127.0.0.1')
parser.add_argument('-p', '--port', default=9000, type=int)
parser.add_argument('--ssl', action='store_true')
args = parser.parse_args()
cherrypy.config.update({'server.socket_host': args.host,
'server.socket_port': args.port,
'tools.staticdir.root': os.path.abspath(os.path.join(os.path.dirname(__file__), 'static'))})
if args.ssl:
cherrypy.config.update({'server.ssl_certificate': './server.crt',
'server.ssl_private_key': './server.key'})
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()
cherrypy.quickstart(Root(args.host, args.port, args.ssl), '', config={
'/ws': {
'tools.websocket.on': True,
'tools.websocket.handler_cls': ChatWebSocketHandler
},
'/js': {
'tools.staticdir.on': True,
'tools.staticdir.dir': 'js'
}
}
)
thread.join()
-
\$\begingroup\$ stackoverflow.com/questions/5839054/websocket-server-in-python check it out \$\endgroup\$outoftime– outoftime2015年01月31日 07:41:31 +00:00Commented Jan 31, 2015 at 7:41
-
\$\begingroup\$ gist.github.com/jkp/3136208 gist from thread above \$\endgroup\$outoftime– outoftime2015年01月31日 07:43:45 +00:00Commented Jan 31, 2015 at 7:43
1 Answer 1
Your code is nice, but it could use a few changes:
% {}
: rather than using that formatting method, you should use thestring.format()
method, involving{0} {1}
instead of%
as it is recommended by PEP8, Python's official style guide.print "exitting therad"
: both exiting and thread are spelt incorrectlyglobal pollStatus
: you shouldn't be naming your variables likecamelCase
, rathersnake_case
instead, as also expressed by PEP8tm=time.localtime()
: you should have whitespace between your binary operators, and also you shouldn't abbreviate your variables liketm
:local_time
would be much better.
Other than that, your code looks nice, well done!
Explore related questions
See similar questions with these tags.