我正在构建一个网络服务器,需要读取(并继续阅读)正在运行的机器的串口。
目的是能够读取条形码扫描仪,并使用服务器发送的事件来更新带有读取条形码的浏览器。
我正在使用烧瓶来做这件事。我浏览过,有些实现只需要烧瓶,有人说我需要像Gevent这样的异步库,还有一些人甚至说我需要Gevent和Redis或RabbitMQ之类的某种队列。
我尝试将我的代码基于stackoverflow here上的一个非常简单的示例。我主要工作,但我遇到了一些问题;
我的代码如下(为清晰起见缩短了)
服务器端:
from flask import Flask
import flask
import serial
app = Flask(__name__)
app.debug = True
def event_barcode():
ser = serial.Serial()
ser.port = 0
ser.baudrate = 9600
ser.bytesize = 8
ser.parity = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
ser.open()
s = ser.read(7)
yield 'data: %s\n\n' % s
@app.route('/barcode')
def barcode():
newresponse = flask.Response(event_barcode(), mimetype="text/event-stream")
newresponse.headers.add('Access-Control-Allow-Origin', '*')
return newresponse
if __name__ == '__main__':
app.run(port=8080, threaded=True)
客户端:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf-8">
<title>TEST</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script>
$(document).ready(function(){
if (!!window.EventSource) {
console.log('SSE supported.');
var source = new EventSource('http://localhost:8080/barcode');
source.addEventListener('message', function(e) {
console.log(e.data);
}, false);
source.addEventListener('open', function(e) {
console.log('Connection was opened.');
}, false);
source.addEventListener('error', function(e) {
if (e.readyState == EventSource.CLOSED) {
console.log('Connection was closed.');
}
}, false);
} else {
console.log('SSE notsupported.');
}
});
</script>
</head>
<body>
</body>
</html>
我在这里看到的更多信息: http://www.socketubs.net/2012/10/28/Websocket_with_flask_and_gevent/ http://sdiehl.github.com/gevent-tutorial/#chat-server
我希望有人可以解决我的问题,并且可能指出我的解决方案,针对跨源和3秒延迟问题。
感谢。
答案 0 :(得分:4)
以下是一些可能有用的要点(我的意思是发布基于'django-sse'的'flask-sse'之类的东西):
https://gist.github.com/3680055
https://gist.github.com/3687523
也很有用 - https://github.com/jkbr/chat/blob/master/app.py
'RedisSseStream'类使用redis作为后端在线程之间进行通信(尽管gevent可以这样做吗?),并且'监听'redis发布事件。
虽然'PeriodicSseStream'不需要redis,但它不能在烧瓶线程之间进行通信,即使用来自另一个响应的信息;没有像redis这样的东西,单独的线程(流和服务于另一个用户的线程)无法通信。
正如Janus所说,生成器只返回一个结果 - 它必须产生多个,并且在这种情况下它必须被包含在一个循环中,在每次串行轮询后无限地产生;您还需要决定限制轮询的内容,是否受时间限制(定期轮询)或其他内容(例如,如果已经花了一段时间来读取串口)?
我真的不太了解sse的性能,或者支持它的程度如何(以及跨域),但是如果你考虑socket.io,你可以使用this来改进网络套接字performance?
答案 1 :(得分:3)
回答我自己的问题
代码:
import flask
import serial
from time import sleep
app = flask.Flask(__name__)
app.debug = True
def event_barcode():
messageid = 0
ser = serial.Serial()
ser.port = 0
ser.baudrate = 9600
ser.bytesize = 8
ser.parity = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
ser.timeout = 0
try:
ser.open()
except serial.SerialException, e:
yield 'event:error\n' + 'data:' + 'Serial port error({0}): {1}\n\n'.format(e.errno, e.strerror)
messageid = messageid + 1
str_list = []
while True:
sleep(0.01)
nextchar = ser.read()
if nextchar:
str_list.append(nextchar)
else:
if len(str_list) > 0:
yield 'id:' + str(messageid) + '\n' + 'data:' + ''.join(str_list) + '\n\n'
messageid = messageid + 1
str_list = []
@app.route('/barcode')
def barcode():
newresponse = flask.Response(event_barcode(), mimetype="text/event-stream")
newresponse.headers.add('Access-Control-Allow-Origin', '*')
newresponse.headers.add('Cache-Control', 'no-cache')
return newresponse
if __name__ == '__main__':
app.run(port=8080, threaded=True)
因为我想支持多种浏览器,所以SSE现在不适合我。我将研究websockets并尝试从中开始工作。