2012-12-24 85 views
2

我建立一個Web服務器,將需要閱讀(繼續閱讀)運行它的計算機的串行端口。
的目的是爲了能夠讀取條形碼掃描儀,以及使用服務器發送的事件來更新與讀取條形碼的瀏覽器。pyserial閱讀瓶串行端口(可能使用GEVENT)

我使用燒瓶做到這一點。我周圍的瀏覽,而且一些實現只需要燒瓶,有人說我需要一個異步庫像GEVENT,有的人甚至說我需要GEVENT和某種類似的Redis或RabbitMQ的隊列。

我試圖立足於一個非常簡單的例子,我在計算器here找到我的代碼。我主要工作,但我堅持一些問題;

  • 在Chrome中有一個跨域錯誤,通過添加 訪問控制允許來源標題我可以得到它在Firefox中, 工作,而Chrome仍然無法正常工作。是否只有FF支持 SSE跨源?我需要它,因爲瀏覽器將 需要從一個單獨的機器加載條碼數據支持CORS。
  • 在每封郵件後,瀏覽器在控制檯中顯示條形碼,但是 它會關閉連接,並且僅在約3秒鐘後再次打開它。看起來這起源於Flask,它給了我數據 ,然後就停止。
  • 此外,我想知道這將如何執行負載。我的意思是,燒瓶 保持連接爲文本/事件流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秒延遲問題。

謝謝。

+0

因爲您使用完整的url客戶端,它讓我想知道你是否在同一個主機和端口上託管客戶端的東西?它是否工作,如果你這樣做(並通過相對網址連接)? –

+1

爲什麼不關閉連接?你給燒瓶一個只能產生一個結果的發生器。 event_barcode()中不應該有某種循環嗎? –

+0

謝謝,Janus;我需要它在不同的主機上運行,​​因爲我需要從公共網站訪問串行端口。我在客戶端(localhost:8080)上運行本地網絡服務器,並通過公共頁面與JavaScript連接。這使我們能夠從瀏覽器訪問本地硬件。這個概念已經可以使用JSONP了,但是使用SSE我不知道如何規避跨源的策略(至少在Chrome中) –

回答

3

回答我自己的問題

  1. 看來,確實只有Firefox支持CORS上證所現在 - > article
  2. 從劍鋒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是不對的,現在去我的方式。我將研究websocket並嘗試從中獲益。

4

這裏有一些學家可以幫助(我一直想推出類似基於「Django的SSE '瓶-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所說,生成器只返回一個結果 - 它必須產生多個結果,在這種情況下,它必須被包含在每次串行輪詢後循環不斷循環的循環中;您還需要決定什麼會限制輪詢,是否會受到時間限制(定期輪詢)或其他事情(例如,如果它已經花了一段時間讀取串行端口)?

我真的不知道很多關於上證所的性能,或如何很好地支持它(和WRT跨域),但如果你考慮socket.io,也許你可以使用this,以提高網絡的插座performance?

+0

謝謝,Chris,但是我恐怕在Python/Flask方面相對比較新,我的頭很小。儘管如此,我仍在試驗。 –