websocket.recv()永远不会在另一个事件循环中返回

时间:2016-06-06 17:33:08

标签: python asynchronous websocket async-await

我目前正在使用websockets和asyncio包在Python中开发服务器程序。

我得到了一个处理websockets工作的基本脚本(图表A)。这个脚本在等待输入时会锁定,这不是我想要的。

我想到的解决方案是我可以启动两个异步任务 - 一个处理输入,一个处理输出 - 并在辅助事件循环中启动它们。我不得不对协同程序进行一些研究,我想出了附件B作为在事件循环中同时运行两件事的概念证明。

现在我所坚持的是图表C.当我尝试在带有websockets包的实际场景中使用它时,我发现websocket.recv()永远不会完成(或者协程永远不会停顿 - 我不确定究竟发生了什么。在展览A中,它运行良好,并且我已经确定协程肯定至少在此之前运行。

有什么想法吗?

图表A:

#!/usr/bin/python3

import asyncio
import websockets
import time

# This works great!
async def hello(websocket, path):
    while True:
        # This line waits for input from socket
        name = await websocket.recv()
        print("< {}".format(name))

        # "echo... echo... echo... echo... echo..."
        greeting = ''.join(name + "... " for x in range(5))
        await websocket.send(greeting)
        print("> {}".format(greeting))

        time.sleep(0.1);

start_server = websockets.serve(hello, '', 26231)

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

图表B:

#!/usr/bin/python3
import asyncio
import time

class Thing:
    def __init__(self):
        pass
    async def test(self):
        for x in range(10):
            print("Hello"+str(x))
            await asyncio.sleep(0)
    def run(self):
        # Add the task to the event loop twice
        asyncio.ensure_future(self.test())
        asyncio.ensure_future(self.test())

t = Thing()
t.run()

loop = asyncio.get_event_loop();
loop.run_forever()

图表C:

#!/usr/bin/python3
import asyncio
import websockets
import time

class WebsocketRequest:
    def __init__(self, websocket):
        self.websocket = websocket

    # Works great
    async def handle_oputs(self):
        # This works fine - sends a message
        #  every 10 seconds to the client
        while True:
            print("sending...")
            await self.websocket.send("Hello")
            print("> {}".format("Hello"))
            time.sleep(10)

    # Doesn't work
    async def handle_iputs(self):
        # This stops at the await and never receives
        #  any input from the client :/
        while True:
            try:
                print("receiving...")
                # This is the line that causes sadness
                data = await self.websocket.recv()
                print("< {}".format(data))
            except:
                # This doesn't happen either
                print("Listener is dead")

    async def run(self):

        # This is the part where the coroutine for
        #  a client get split off into two of them
        #  to handle input and output separately.
        loop = asyncio.new_event_loop()

        asyncio.set_event_loop(loop)
        asyncio.ensure_future(self.handle_iputs())
        asyncio.ensure_future(self.handle_oputs())

        loop.run_forever()

class WebsocketServer:
    def __init__(self, address):
        self.ip = address[0]
        self.port = address[1]


    async def hello(self, websocket, path):
        req = WebsocketRequest(websocket)
        await req.run()

    def run(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        start_server = websockets.serve(self.hello, self.ip, self.port)

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

2 个答案:

答案 0 :(得分:0)

也许模块websocket(与websockets不同)可以帮助你。

使用WebsocketApp非常简单:

from websocket import WebSocketApp    

class ExampleClass(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org",
                                    on_message=on_message,
                                    on_error=on_error,
                                    on_close=on_close)

    def on_message(ws, msg):
        print "Message Arrived:" + msg

    def on_error(ws, error):
        print error

    def on_close(ws):
        print "Connection Closed"

    def on_open(ws):
       ws.send("Hello!")

要下载此模块:https://pypi.python.org/pypi/websocket-client

答案 1 :(得分:0)

time.sleep()是一个阻塞操作,因此任何其他任务都不能中断,也不会被安排。请改用await asyncio.sleep()