pyserial读取Flask中的串行端口(可能使用gevent)

2024-05-14 23:05:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在构建一个web服务器,它需要读取(并继续读取)它运行的机器的串行端口。
其目的是能够读取条形码扫描仪,并使用服务器发送的事件用读取的条形码更新浏览器。

我用烧瓶来做这个。我浏览了一下,有些实现只需要flask,有些说我需要一个像Gevent这样的异步库,有些甚至说我需要Gevent和一些像Redis或RabbitMQ这样的队列。

我试图将代码建立在stackoverflowhere上的一个非常简单的示例上。我有它的主要工作,但我被困在一些问题

  • 在Chrome中,通过添加 访问控制允许来源头我可以让它在火狐工作, 但Chrome仍然不起作用。是否只有FF支持 SSE交叉源?我需要它来支持CORS,因为浏览器会 需要从单独的机器加载条码数据。
  • 在每条消息之后,浏览器在控制台中显示条形码,但是 然后关闭连接,大约3点后再打开 几秒钟。这似乎源于烧瓶,它给了我数据 然后就停下来。
  • 另外,我想知道这将如何执行负载。我是说,烧瓶 为文本/事件流mimetype保持连接打开。如果 多个客户端连接,过一段时间不会阻塞烧瓶,因为 所有的连接都会饱和?

我的代码如下(为清楚起见,简称)

服务器端:

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秒延迟问题。

谢谢。


Tags: logapphttpflasksource烧瓶serialscript
2条回答

回答我自己的问题

  1. 似乎目前只有Firefox支持SSE的CORS->; article
  2. 在Janus Troelsen的帮助下我找到了 连接打开并跨行发送多个条形码(请参见代码 以下)
  3. 就性能而言,我似乎只能建立一个连接,但是 那可能是因为我只有一个串行端口 连接无法再打开串行端口。我想会有用的 从烧瓶里拿出来的,但是有socketio和gevents的东西会用的 更好,因为它更适合这份工作。有一个有趣的 文章here

对于代码:

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并尝试从中学习。

以下是一些可能有帮助的建议(我一直想发布一些类似基于“django sse”的“flask sse”:

https://gist.github.com/3680055

https://gist.github.com/3687523

也有用-https://github.com/jkbr/chat/blob/master/app.py

“redissestream”类使用redis作为后端在线程之间进行通信(尽管gevent可以做到这一点?),并“侦听”redis发布事件。

虽然“PeriodicSseStream”不需要redis,但它不能在烧瓶线程之间进行通信,即使用来自另一个响应的信息;没有像redis这样的东西,单独的线程(流和为另一个用户服务的线程)就不能通信。

正如Janus所说,生成器只返回一个结果-它必须产生多个结果,在这种情况下,它必须被封装在一个循环中,在每次串行轮询之后都会无休止地产生结果;您还需要决定什么将限制轮询,它是受时间限制(定期轮询)还是其他限制(例如,如果读取串行端口已经花了一段时间)?

我不太了解sse的性能,也不知道它的支持程度(以及wrt跨域),但是如果考虑socket.io,您可以使用this来改进web套接字performance?

相关问题 更多 >

    热门问题