在python asyncio

时间:2018-01-23 04:45:06

标签: python websocket python-asyncio

我认为我的问题非常容易和愚蠢,但我阅读了很多材料,无法想象如何做我想做的事。

所以,我使用websockets库,我有这个algorythm:

# 1. get connection and start handle it
async def main_request_handler(ws, path):
    proxy = Proxy()
    try:
        await proxy.start(ws, path)

2。在内部开始我创建第二个websocket来传递来自ws的请求并接收答案以将它们发送到ws

while True:
    request_raw = await self.ws_server.recv()
    await self.process_request_from_server(request_raw)

问题是,我需要使用一个websocket服务器连接进行乘法运算 ws个客户,我需要从ws_server向每个人传达相同的答案。现在我只得到一个响应,因为.recv()只返回一个'订阅者的值。 如何解决这个问题?请注意,我使用while Trueasync

4 个答案:

答案 0 :(得分:2)

这是一个非常简单的pub / sub websockets服务器示例

import asyncio
import websockets

connections = set()
n = 0


async def handler(websocket, path):
    global n

    if path == "/sub":
        n = n + 1
        i = n
        connections.add(websocket)
        print("adding subscriber #", i)
        try:
            async for msg in websocket:
                pass  # ignore
        except websockets.ConnectionClosed:
            pass
        finally:
            print("removing subscriber #", i)
            connections.remove(websocket)

    elif path == "/pub":
        async for msg in websocket:
            print("<", msg)
            for ws in connections:
                asyncio.ensure_future(ws.send(msg))


start_server = websockets.serve(handler, 'localhost', 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

一个示例订户客户端(运行其中一些):

import asyncio
import websockets


async def listen():
    async with websockets.connect('ws://localhost:8765/sub') as websocket:
        while True:
            greeting = await websocket.recv()
            print("< {}".format(greeting))


asyncio.get_event_loop().run_until_complete(listen())

和出版商:

import asyncio
import websockets


async def say():
    async with websockets.connect('ws://localhost:8765/pub') as websocket:
        while True:
            msg = input("Enter message:")
            if not msg:
                break
            await websocket.send(msg)


asyncio.get_event_loop().run_until_complete(say())

答案 1 :(得分:1)

  

换句话说,我需要在同一个循环中运行.recv并与多个使用者一起运行。在RxPy中我只能stream.emit(recv_result)并使用像thatstrem.subscribe(callback_fn)这样的项目,但这是回调方式,我需要异步

您的subscribe方法可以接受协程功能,即使用async def创建的功能。一旦发出某些内容,就可以实例化它们,并使用create_task生成它们的协同程序:

def __init__(self, ...):
    self._subscribers = []

def subsribe(self, corofn):
    self._subscribers.append(corofn)

def emit(self, obj):
    loop = asyncio.get_event_loop()
    for corofn in self._subscribers:
        coro = corofn(obj)
        loop.create_task(coro)

async def main(self):
    while True:
        request_raw = await self.ws_server.recv()
        self.emit(request_raw)

答案 2 :(得分:0)

我不确定我是否理解正确,但不是gathering多个协同程序是你想要的吗?

while True:
    request_raw = await self.ws_server.recv()

    # process by multiple clients parallely:
    await asyncio.gather(
        self.process_by_client_1(request_raw),
        self.process_by_client_2(request_raw),
        self.process_by_client_3(request_raw),
    )

答案 3 :(得分:0)

感谢您的建议,他们可能会工作。我是通过队列完成的。

class SWebsocket(object):

    def __init__(self, websocket: WebSocketServerProtocol):
        self.ws = websocket
        self.queues = {}
        self.subscribe()

    def subscribe(self):
        # fire and forget function
        asyncio.ensure_future(self.recv_mess())

    async def recv_mess(self):
        while True:
            try:
                data = await self.ws.recv()
            except websockets.ConnectionClosed as e:
                for _, q in self.queues.items():
                    await q.put(e)
                return
            for _, q in self.queues.items():
                await q.put(data)

    async def recv(self, id):
        # read value from queue
        if id not in self.queues:
            self.queues[id] = asyncio.Queue()
        data = await self.queues[id].get()
        if isinstance(data, websockets.ConnectionClosed):
            raise data
        return data