Python 异步IO协议/服务器之间的通信
我正在尝试编写一个服务器端事件服务器,可以通过telnet连接到该服务器,并将telnet内容推送到浏览器。使用Python和asyncio背后的想法是尽可能少地使用CPU,因为这将在Raspberry Pi上运行 到目前为止,我有以下使用这里找到的库的代码:使用asyncio 我还复制了一个使用asyncio的telnet服务器 两者都是分开工作的,但我不知道如何将两者结合在一起。据我所知,我需要从Python 异步IO协议/服务器之间的通信,python,python-asyncio,Python,Python Asyncio,我正在尝试编写一个服务器端事件服务器,可以通过telnet连接到该服务器,并将telnet内容推送到浏览器。使用Python和asyncio背后的想法是尽可能少地使用CPU,因为这将在Raspberry Pi上运行 到目前为止,我有以下使用这里找到的库的代码:使用asyncio 我还复制了一个使用asyncio的telnet服务器 两者都是分开工作的,但我不知道如何将两者结合在一起。据我所知,我需要从Telnet.data\u received内部调用SSEHandler类中的send(),但我
Telnet.data\u received
内部调用SSEHandler
类中的send()
,但我不知道如何访问它。这两个“服务器”都需要在循环中运行,以接受新连接或推送数据
有人能帮我吗,或者给我指出另一个方向
import asyncio
import sse
# Get an instance of the asyncio event loop
loop = asyncio.get_event_loop()
# Setup SSE address and port
sse_host, sse_port = '192.168.2.25', 8888
class Telnet(asyncio.Protocol):
def connection_made(self, transport):
print("Connection received!");
self.transport = transport
def data_received(self, data):
print(data)
self.transport.write(b'echo:')
self.transport.write(data)
# This is where I want to send data via SSE
# SSEHandler.send(data)
# Things I've tried :(
#loop.call_soon_threadsafe(SSEHandler.handle_request());
#loop.call_soon_threadsafe(sse_server.send("PAH!"));
def connection_lost(self, esc):
print("Connection lost!")
telnet_server.close()
class SSEHandler(sse.Handler):
@asyncio.coroutine
def handle_request(self):
self.send('Working')
# SSE server
sse_server = sse.serve(SSEHandler, sse_host, sse_port)
# Telnet server
telnet_server = loop.run_until_complete(loop.create_server(Telnet, '192.168.2.25', 7777))
#telnet_server.something = sse_server;
loop.run_until_complete(sse_server)
loop.run_until_complete(telnet_server.wait_closed())
服务器端事件是一种http协议;在任何给定的时刻,您可能会有任意数量的并发http请求,如果没有人连接,您可能会有零个,或者几十个。这种细微差别都包含在两个
sse.service
和sse.Handler
结构中;前者表示单个侦听端口,将每个单独的客户端请求分派给后者
此外,为每个客户端调用一次sse.Handler.handle_request()
,并且一旦co例程终止,客户端将断开连接。在您的代码中,该协同路由立即终止,因此客户端会看到一个“工作”事件。所以,我们需要等待,或多或少永远。我们可以通过从ing一个asyncio.Future()
第二个问题是,我们需要以某种方式获得SSEHandler()
的所有单独实例,并以某种方式在每个实例上使用send()
方法。好的,我们可以让每个人在他们的handle\u request()
方法中进行自我注册;通过将每个实例添加到dict,dict将单个处理程序实例映射到它们等待的未来
class SSEHandler(sse.Handler):
_instances = {}
@asyncio.coroutine
def handle_request(self):
self.send('Working')
my_future = asyncio.Future()
SSEHandler._instances[self] = my_future
yield from my_future
现在,要向每个侦听发送事件,我们只需访问我们创建的dict中注册的所有SSEHandler实例,并在每个实例上使用send()
class SSEHandler(sse.Handler):
#...
@classmethod
def broadcast(cls, message):
for instance, future in cls._instances.items():
instance.send(message)
class Telnet(asyncio.Protocol):
#...
def data_received(self, data):
#...
SSEHandler.broadcast(data.decode('ascii'))
最后,您的代码在telnet连接关闭时退出。那很好,但我们那时也应该清理一下。幸运的是,这只是为所有处理程序的所有未来设置结果的问题
class SSEHandler(sse.Handler):
#...
@classmethod
def abort(cls):
for instance, future in cls._instances.items():
future.set_result(None)
cls._instances = {}
class Telnet(asyncio.Protocol):
#...
def connection_lost(self, esc):
print("Connection lost!")
SSEHandler.abort()
telnet_server.close()
这里有一个完整的工作转储,以防我的说明不明显
import asyncio
import sse
loop = asyncio.get_event_loop()
sse_host, sse_port = '0.0.0.0', 8888
class Telnet(asyncio.Protocol):
def connection_made(self, transport):
print("Connection received!");
self.transport = transport
def data_received(self, data):
SSEHandler.broadcast(data.decode('ascii'))
def connection_lost(self, esc):
print("Connection lost!")
SSEHandler.abort()
telnet_server.close()
class SSEHandler(sse.Handler):
_instances = {}
@classmethod
def broadcast(cls, message):
for instance, future in cls._instances.items():
instance.send(message)
@classmethod
def abort(cls):
for instance, future in cls._instances.items():
future.set_result(None)
cls._instances = {}
@asyncio.coroutine
def handle_request(self):
self.send('Working')
my_future = asyncio.Future()
SSEHandler._instances[self] = my_future
yield from my_future
sse_server = sse.serve(SSEHandler, sse_host, sse_port)
telnet_server = loop.run_until_complete(loop.create_server(Telnet, '0.0.0.0', 7777))
loop.run_until_complete(sse_server)
loop.run_until_complete(telnet_server.wait_closed())
非常感谢您解释如何以及为什么,非常有用。看来我还有很多东西要学。我让您的示例代码运行,它正是我想要/需要的,而且CPU非常低。再次感谢