通过python websocket重播基于计时器的数据

时间:2020-01-30 10:47:58

标签: python websocket python-asyncio

目前,我正在开发一个IoT Mockup Client,它可以读取几个真实的时间序列数据CSV,并根据其时间戳和系统时钟(threading模块)“重放”它们。

所以基本上我有一个Pandas数据框,其中保存了所有旧数据,还有一个计时器滴答处理程序函数,该函数从中提取相应的行以将其输出到任何数据接收器。

如果我的计时器处理程序使用requests.post(..然后仅发布从df[...<current-timeslice-filer>...].to_csv()收集的文本正文,则此方法非常有效。

现在,我想将此数据流传输到服务器api,因此我们决定通过Websockets而不是HTTP-REST传输数据。事情开始变得棘手。 websockets模块高度依赖asyncio,它需要自己的事件循环。因为我的计时器已经是一个事件循环(基于threading.timer),并且我必须承认我不完全了解asyncio的概念,所以我认为这不太适合。

至少我不知道如何将websocket.send()方法集成到我的处理程序方法中,以便使其在asyncio事件循环内运行。

DataFrame.to_csv(...可以被赋予文件处理程序file_or_buf,我将不胜感激,像文件处理程序一样使用websocket并在此处提供它,以刷新我的数据。

  • Python中是否还有另一个使用此范例的websocket实现?
  • 可以使用websockets模块来实现这一目标吗?我只是看错了吗?
  • 我是否还必须使用asyncio实现基于时间间隔的数据发送处理程序,以便两者都在事件循环中运行?

编辑到目前为止的内容...

那是我的计时器类,每do()秒调用一次方法interval

from threading import Thread,Event

class TimeTicker(Thread):
    def __init__(self, interval=1):
        Thread.__init__(self)
        self.interval = interval
        self.stopped = Event()

    def run(self):
        while not self.stopped.wait(self.interval):
            self.do()

    def do(self):
        print('tick')

    def get_stopflag(self):
        return self.stopped

现在,使用websocketsasyncio的基本代码是...

import asyncio
import websockets

async def hello():
    uri = "ws://echo.websocket.org"
    async with websockets.connect(uri) as websocket:
        await websocket.send(thread.stream())
        r = await websocket.recv()
        print(r)

asyncio.get_event_loop().run_until_complete(hello())

我已经尝试过创建do()方法async,但是我无法在asyncio事件循环内初始化TimeTicker类,因此“等待”方法调用

为使情况更清楚,我想在TimeTicker对象外部初始化websocket连接(它仅应每秒提供时间序列数据并将其传递给websocket.send()。尽管如此,我不确定该数据传递应该在哪里这样的话,也许还有更好的TimeTicker类解决方案来每秒yield数据,而不仅仅是调用方法。总之,我想就此寻求建议。

提示:TimeTicker只是我的数据源类的一个超类,它实际上保存着大约为pandas的数据帧。从CSV读取20万行时间序列数据作为要发送的存储库。

解决方案:基于@ wowkin2的答案,现在我的TimeTicker类仅通过asyncio即可实现...

import asyncio
import websockets


class TimeTicker:
    is_stopped = False

    def __new__(cls, _loop, _uri, interval=1):
        instance = super().__new__(cls)
        instance.interval = interval
        instance.uri = _uri
        instance.task = _loop.create_task(instance.run())
        return instance.task

    async def run(self):
        async with websockets.connect(self.uri) as self.ws:
            while True:
                await self.do()
                await asyncio.sleep(self.interval)

    async def do(self):
        message = 'ping'
        await self.ws.send(message)
        r = await self.ws.recv()
        print(r)

    def stop(self):
        self.task.cancel()
        self.is_stopped = True

uri = "ws://echo.websocket.org"
loop = asyncio.get_event_loop()
task = TimeTicker(loop, uri, interval=5)
loop.run_until_complete(task)

1 个答案:

答案 0 :(得分:1)

如果使用asyncio,则不需要线程模块。

这里是一个示例,说明如何使用asyncio定期执行某项操作。 唯一的事情-您将需要具有始终打开的连接且没有上下文管理器的变量。

import asyncio


class TimeTicker:
    is_stopped = False

    def __new__(cls, _loop, _ws, interval=1):
        instance = super().__new__(cls)
        instance.interval = interval
        instance.ws = _ws
        instance.task = _loop.create_task(instance.run())
        return instance.task

    async def run(self):
        while True:
            await self.do()
            await asyncio.sleep(self.interval)

    async def do(self):
        message = 'ping'
        await self.ws.send(message)
        r = await self.ws.recv()
        print(r)

    def stop(self):
        self.task.cancel()
        self.is_stopped = True


uri = "ws://echo.websocket.org"
ws = websockets.connect(uri)

loop = asyncio.get_event_loop()
task = TimeTicker(loop, ws, interval=5)
loop.run_until_complete(task)