[英]OOP Python websockets
I'd like to encapsulate the functionality of the python websockets package into a class, representing a sensor coordinator.我想将 python websockets包的功能封装到一个类中,代表一个传感器协调器。 The aim of this is to allow me to create a coordinator object, and only have the server persist for as long as it is needed.
这样做的目的是让我创建一个协调器对象,并且只在需要时让服务器持续存在。 Unfortunately, I have not been able to find any similar examples of this online and have so far struggled.
不幸的是,我无法在网上找到任何类似的例子,并且到目前为止一直在努力。
My code is as follows:我的代码如下:
import asyncio
import json
import logging
import websockets
logging.basicConfig()
class Coordinator(object):
def __init__(self, host='localhost', port=8080):
self.host = host
self.port = port
self.running = False
self.server = None
self.sensors = set()
def __enter__(self):
self.server = websockets.serve((self.ws_handler, self.host, self.port))
self.running = True
def __exit__(self, exc_type, exc_val, exc_tb):
# Gracefully stop serving
self.running = False
pass
def sensors_event(self):
return json.dumps({'type': 'sensors', 'count': len(self.sensors)})
async def notify_sensors(self):
if self.sensors:
message = self.sensors_event()
await asyncio.wait([user.send(message) for user in self.sensors])
async def register(self, websocket):
self.sensors.add(websocket)
await self.notify_sensors()
async def unregister(self, websocket):
self.sensors.remove(websocket)
await self.notify_sensors()
async def ws_handler(self, websocket):
try:
await self.register(websocket)
pass
finally:
await self.unregister(websocket)
if __name__ == '__main__':
with Coordinator() as coordinator:
pass
At the moment it would appear that the websocket server does not start, as it is not visible on netstat.目前看来 websocket 服务器没有启动,因为它在 netstat 上不可见。
Would it be possible to run the server in a separate (demonised) thread, held by the coordinator object?是否可以在由协调器对象持有的单独(妖魔化)线程中运行服务器?
Thanks谢谢
From the high-level documentation :来自高级文档:
The
websockets.server
module defines a simpleWebSocket
server API.websockets.server
模块定义了一个简单的WebSocket
服务器 API。
serve()
returns an awaitable.serve()
返回一个可等待的。 Awaiting it yields an instance ofWebSocketServer
which providesclose()
andwait_closed()
methods for terminating the server and cleaning up its resources.等待它会产生一个
WebSocketServer
实例,它提供close()
和wait_closed()
方法来终止服务器并清理其资源。On Python ≥ 3.5,
serve()
can also be used as an asynchronous context manager.在 Python ≥ 3.5 上,
serve()
也可以用作异步上下文管理器。 In this case, the server is shut down when exiting the context.在这种情况下,服务器在退出上下文时关闭。
As @user4815162342 already identified, the main issue is that you do not await the call to the serve()
coroutine.正如@user4815162342 已经确定的那样,主要问题是您没有等待对
serve()
协程的调用。
Since you're using Python v3.6.8 you can use the asynchronous context manager to simplify the implementation.由于您使用的是 Python v3.6.8,您可以使用异步上下文管理器来简化实现。 The benefit of this is that you do not need to worry about handling shutdown, since it is handled automatically.
这样做的好处是您无需担心处理关机,因为它是自动处理的。 Here's an object oriented implementation of a simple echo server.
这是一个简单的回显服务器的面向对象的实现。
import asyncio
import signal
import websockets
class Server(object):
def __init__(self, host, port):
self.host, self.port = host, port
self.loop = asyncio.get_event_loop()
self.stop = self.loop.create_future()
self.loop.add_signal_handler(signal.SIGINT, self.stop.set_result, None)
self.loop.run_until_complete(self.server())
async def server(self):
async with websockets.serve(self.ws_handler, self.host, self.port):
await self.stop
async def ws_handler(self, websocket, path):
msg = await websocket.recv()
print(f'Received: {msg}')
await websocket.send(msg)
print(f'Sending: {msg}')
if __name__ == '__main__':
server = Server(host='localhost', port=6789)
At the moment, this will run until the user sends an interrupt, but you can adjust the stop
future to suit.目前,这将一直运行直到用户发送中断,但您可以调整
stop
未来以适应。
Your code has two issues.您的代码有两个问题。
You never start the asyncio main loop, so asyncio has no chance of ever running.你永远不会启动 asyncio 主循环,所以 asyncio 没有机会运行。 In other words, you need to have
loop.run_until_complete(x)
somewhere in your code.换句话说,您需要在代码中的某处使用
loop.run_until_complete(x)
。
start_server
is a coroutine, so you must await it. start_server
是一个协程,所以你必须等待它。
A fixed version of the code (but untested) might look like this:代码的固定版本(但未经测试)可能如下所示:
class Coordinator(object):
def __init__(self, host='localhost', port=8080):
self.host = host
self.port = port
self.running = False
self.server = None
self.sensors = set()
async def __aenter__(self):
self.server = await websockets.serve((self.ws_handler, self.host, self.port))
self.running = True
def __aexit__(self, exc_type, exc_val, exc_tb):
# Gracefully stop serving
self.running = False
def sensors_event(self):
return json.dumps({'type': 'sensors', 'count': len(self.sensors)})
async def notify_sensors(self):
if self.sensors:
message = self.sensors_event()
await asyncio.wait([user.send(message) for user in self.sensors])
async def register(self, websocket):
self.sensors.add(websocket)
await self.notify_sensors()
async def unregister(self, websocket):
self.sensors.remove(websocket)
await self.notify_sensors()
async def ws_handler(self, websocket):
try:
await self.register(websocket)
finally:
await self.unregister(websocket)
async def main():
async with Coordinator() as coordinator:
pass
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(main())
It will be much easier to use asyncio if you take the time to go through a tutorial that covers basic asyncio concepts, such as running the main loop.如果您花时间阅读涵盖基本 asyncio 概念(例如运行主循环)的教程,则使用 asyncio 会容易得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.