简体   繁体   English

如何在龙卷风中使用多个ioloop并在ioloop之间共享数据?

[英]How to use multiple ioloop in tornado and share data between the ioloop(s)?

I have a Beaglebone Black connect to a CAN bus devices: Battery. 我有一个Beaglebone Black连接到CAN总线设备:电池。

A tornado web running on Beaglebone Black as GUI. 在Beaglebone Black上运行的龙卷风网作为GUI。

CAN bus reading loop keep reading data from CAN bus to update the status of Battery instance CAN总线读取循环不断从CAN总线读取数据以更新Battery实例的状态

But how can I make the two IOLOOP work together and share Battery instance? 但是,如何使两个IOLOOP一起工作并共享Battery实例呢?

在此处输入图片说明

tornado web: 龙卷风网:

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 bus reading loop, code: 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()

As I can see you are running two applications, so it will be difficult to share instance of Battery. 如我所见,您正在运行两个应用程序,因此很难共享Battery实例。 First solution - combine all functionality in one application so Battery instance will be simply available, but you will face challenges with serving HTTP requests and handling socket events from CAN in one ioloop. 第一个解决方案-将所有功能组合在一个应用程序中,这样就可以轻松使用Battery实例,但是在HTTP请求和在一个ioloop中处理来自CAN的套接字事件时,您将面临挑战。

So here is another solution, keep two application but not try to share a Battery instance, just make an http request from CAN listener to your GUI app. 因此,这是另一种解决方案,保留两个应用程序,但不尝试共享Battery实例,仅从CAN侦听器向您的GUI应用程序发出http请求。

For example in CAN file: 例如在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)))

Would be better to use urlencode from python urllib to encode body if you have bytes in data. 如果您的数据中有字节,最好使用python urllib中的 urlencode 编码正文

In GUI file: 在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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM