搞了幾天,順便把代碼貼這里,需要的 python 包:
gevent,gevent-websocket,bottle,wiringpi-python
簡單說明:
- gevent 提供了支持 concurrent,以及 concurrent 下的 socket 操作。注意,引入 monkey 后,socket 就是 genvent 封裝過的了,不再是系統原生 socket。
- 連接到 /ws 后,鏈接為長鏈接,使用 gevent.Timeout() 提供的 alarm 來周期執行 sensor 讀操作,並將讀到的數據發送給 client。
- 瀏覽器端,直接訪問根目錄,返回是一個 web client,提供了一個 textarea,將 server 發來的數據顯示出來。
- 瀏覽器端,沒有寫發送,需要的話可以按 F12 在 console 里面,直接調用 ws.send('your_message') 來想服務器發送。
from bottle import route, run, request, abort, Bottle, static_file from gevent import monkey; monkey.patch_all() from gevent import sleep, Timeout import wiringpi import serial app = Bottle() host = '0.0.0.0' port = 8080 SensorData = '' fdI2c = wiringpi.wiringPiI2CSetup(0x40) ser = serial.Serial("/dev/ttyUSB0", 9600, timeout = 0.1) def readSensor(): global SensorData serBuffer = ser.readline().rstrip() if len(serBuffer) == 0: serBuffer = "0"; strength = wiringpi.wiringPiI2CReadReg16(fdI2c, 0x1c); position = wiringpi.wiringPiI2CReadReg16(fdI2c, 0x0c); angle = wiringpi.wiringPiI2CReadReg16(fdI2c, 0x0e); SensorData = serBuffer + ":" \ + str(strength) + ":" \ + str(position) + ":" \ + str(angle); @app.route('/ws') def handle_websocket(): wsock = request.environ.get('wsgi.websocket') if not wsock: abort(400, 'Expected WebSocket request.') while True: try: global SensorData with Timeout(0.5, False) as timeout: message = wsock.receive() if not message: readSensor() message = SensorData wsock.send("%r" % message) message = u'' except WebSocketError: break @app.route('/') def send_index(): return """<html> <head> <script type='application/javascript' src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> var ws = new WebSocket("ws://%(host)s/ws"); ws.onopen = function() { ws.send("Hello, world"); }; ws.onmessage = function (evt) { $('#chat').val($('#chat').val() + evt.data + '\\n'); }; </script> </head> <body> <form action='#' id='chatform' method='get'> <textarea id='chat' cols='100' rows='20'></textarea> </form> </body> </html>"""%{'host':request.headers.get('Host')} from gevent.pywsgi import WSGIServer from geventwebsocket.handler import WebSocketHandler from geventwebsocket import WebSocketError server = WSGIServer((host, port), app, handler_class=WebSocketHandler) print "access @ http://%s:%s" % (host, port) server.serve_forever()
上面的 timeout 函數是為了給 wsock.receive() 提供充足的時間,使其在這段時間內一直等待接收狀態。
另外可以用 sleep() (注意, sleep 是從 gevent 引入的,並不是 time 那個 sleep)來交出 gevent 控制權,讓其它協程獲得 CPU。