2017-08-17 446 views
0

我有一个可以通过websocket端点使用的python服务器。 在服务连接期间,它也与一些后端服务进行通信。这种通信是异步的,可能会触发websocket的send()方法。Python websocket卡住

当一个客户端供应,似乎工作正常。但是,当并行服务多个客户端时,处理连接的一些例程偶尔会卡住。更确切地说,它似乎阻止了recv()方法。

实际的代码是有点复杂,问题会更复杂一些比我所描述的,不过,我提供最少的代码框架是素描的方式,我用他的WebSockets:

class MinimalConversation(object): 

    def __init__(self, ws, worker_sck, messages, should_continue_conversation, should_continue_listen): 
     self.ws = ws 
     self.messages = messages 
     self.worker_sck = worker_sck 
     self.should_continue_conversation = should_continue_conversation 
     self.should_continue_listen = should_continue_listen 

async def run_conversation(self): 
     serving_future = asyncio.ensure_future(self.serve_connection()) 
     listening_future = asyncio.ensure_future(self.handle_worker()) 
     await asyncio.wait([serving_future, listening_future], return_when=asyncio.ALL_COMPLETED) 

async def serve_connection(self): 
     while self.should_continue_conversation(): 
      await self.ws.recv() 
      logger.debug("Message received") 
      self.sleep_randomly(10, 5) 
      await self.worker_sck.send(b"Dummy") 

async def handle_worker(self): 
     while self.should_continue_listen(): 
      self.sleep_randomly(50, 40) 
      await self.worker_sck.recv() 
      await self.ws.send(self.messages.pop()) 

def sleep_randomly(self, mean, dev): 
     delta = random.randint(1, dev)/1000 
     if random.random() < .5: 
      delta *= -1 
     time.sleep(mean/1000 + delta) 

显然,在真实的代码中,我不会随机间隔休眠,也不会使用给定的消息列表,但是这将勾画出我处理websocket的方式。在真实环境中,可能会发生通过websocket发送的错误,因此理论上可能会发生并行发送(),但我从未遇到过这种情况。

该代码是从),其被作为参数传递到websockets.serve(一个处理程序函数运行,初始化MinimalConversation对象,并调用run_conversation()方法。

我的问题是:

  • 有什么根本性的错误的的WebSockets的这种用法?
  • send()方法的并发调用是否危险?
  • 你可以提出一些有关websockets和asyncio使用的良好做法吗?

Thak你。

回答

1

recv函数仅在接收到消息时返回,并且似乎有两个连接正在等待来自对方的消息,所以在等待对方的消息时可能会出现类似于“死锁”的情况,并且可以不发送任何东西。也许你应该尝试重新思考整体算法,以便更安全。

,当然,尝试将更多的调试输出,看看到底发生了什么。

是在send()方法危险的并发呼叫?

如果你同时表示在同一线程中,但在独立调度的协同程序中,那么并行发送就好了。但要小心“平行” recv相同的连接上,因为协程调度顺序可能远离明显,它就是决定哪些来电recv首先会得到一个消息。

你可以提出一些有关websockets和asyncio使用的良好做法吗?

根据我的经验,最简单的方法是为传入连接创建一个专用任务,这将连续呼叫recv,直到连接关闭。您可以将连接存储在某个地方,并在finally区块中将其删除,然后可以从其他协同程序使用它来发送内容。