[英]How to use multiple ioloop in tornado and share data between the ioloop(s)?
我有一個Beaglebone Black連接到CAN總線設備:電池。
在Beaglebone Black上運行的龍卷風網作為GUI。
CAN總線讀取循環不斷從CAN總線讀取數據以更新Battery實例的狀態
但是,如何使兩個IOLOOP一起工作並共享Battery實例呢?
龍卷風網:
class Battery(object):
status = {}
class API_Handler(web.RequestHandler):
def get(self, dev, cmd):
if cmd == 'data':
self.write(self.application.battery0.status)
class Application(web.Application):
def __init__(self):
self.battery0 = Battery('bat0')
routing = [
(r'/api/battery/(data|)', API_Handler),
]
settings = {
'template_path': os.path.join(os.path.dirname(__file__), "templates"),
'static_path': os.path.join(os.path.dirname(__file__), "static"),
}
web.Application.__init__(self, routing, debug=True, **settings)
if __name__ == "__main__":
import tornado
app = Application()
app.listen(address='0.0.0.0', port=8888)
tornado.ioloop.IOLoop.instance().start()
CAN總線讀取循環,代碼:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import errno
import functools
import tornado.ioloop
import socket
import struct
can_frame_fmt = "=IB3x8s"
can_frame_size = struct.calcsize(can_frame_fmt)
def build_can_frame(can_id, data):
can_dlc = len(data)
data = data.ljust(8, b'\x00')
return struct.pack(can_frame_fmt, can_id, can_dlc, data)
def dissect_can_frame(frame):
can_id, can_dlc, data = struct.unpack(can_frame_fmt, frame)
return (can_id, can_dlc, data[:can_dlc])
def connection_ready(sock, fd, events):
while True:
try:
cf, addr = sock.recvfrom(can_frame_size)
except socket.error as e:
if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
raise
return
dissect_can_frame(cf)
if __name__ == '__main__':
sock = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
sock.bind(('can0',))
sock.setblocking(0)
io_loop = tornado.ioloop.IOLoop.current()
callback = functools.partial(connection_ready, sock)
io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
io_loop.start()
如我所見,您正在運行兩個應用程序,因此很難共享Battery實例。 第一個解決方案-將所有功能組合在一個應用程序中,這樣就可以輕松使用Battery實例,但是在HTTP請求和在一個ioloop中處理來自CAN的套接字事件時,您將面臨挑戰。
因此,這是另一種解決方案,保留兩個應用程序,但不嘗試共享Battery實例,僅從CAN偵聽器向您的GUI應用程序發出http請求。
例如在CAN文件中:
from tornado.httpclient import AsyncHTTPClient
...
def connection_ready(sock, fd, events):
while True:
try:
cf, addr = sock.recvfrom(can_frame_size)
except socket.error as e:
if e.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
raise
return
http_client = AsyncHTTPClient()
http_client.fetch("http://localhost:8888/update-battery",
method="POST",
body="can_id={}&can_dlc={}&data={}".format(
dissect_can_frame(cf)))
如果您的數據中有字節,最好使用python urllib中的 urlencode 編碼正文 。
在GUI文件中:
class Battery_Update_Handler(web.RequestHandler):
def post(self):
self.application.battery0.status = dict(
can_id=self.get_argument("can_id", None),
can_dlc=self.get_argument("can_dlc", None),
data=self.get_argument("data", None))
class Application(web.Application):
def __init__(self):
self.battery0 = Battery('bat0')
routing = [
(r'/api/battery/(data|)', API_Handler),
(r'/update-battery', Battery_Update_Handler)
]
settings = {
'template_path': os.path.join(os.path.dirname(__file__), "templates"),
'static_path': os.path.join(os.path.dirname(__file__), "static"),
}
web.Application.__init__(self, routing, debug=True, **settings)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.