我试图在python中创建一个使用websockets和asyncio来监听多个套接字的脚本,问题是无论我做什么,它只会听我调用的第一个套接字。 我认为它是无限循环,我有什么选择来解决这个问题?为每个套接字使用线程?
async def start_socket(self, event):
payload = json.dumps(event)
loop = asyncio.get_event_loop()
self.tasks.append(loop.create_task(
self.subscribe(event)))
# this should not block the rest of the code
await asyncio.gather(*tasks)
def test(self):
# I want to be able to add corotines at a different time
self.start_socket(event1)
# some code
self.start_socket(event2)
答案 0 :(得分:1)
您的代码似乎不完整,但您展示的内容有两个问题。一个是run_until_complete
接受一个协程对象(或其他类型的未来),而不是协程函数。所以它应该是:
# note parentheses after your_async_function()
asyncio.get_event_loop().run_until_complete(your_async_function())
问题是无论我做什么,它只会听我拨打的第一个插座。我认为它是无限循环,我有什么选择来解决这个问题?为每个套接字使用线程?
无限循环不是问题,asyncio旨在支持这种“无限循环”。问题是你试图在一个协程中做所有事情,而你应该为每个websocket创建一个协同程序。这不是问题,因为协同程序非常轻量级。
例如(未经测试):
async def subscribe_all(self, payload):
loop = asyncio.get_event_loop()
# create a task for each URL
for url in url_list:
tasks.append(loop.create_task(self.subscribe_one(url, payload)))
# run all tasks in parallel
await asyncio.gather(*tasks)
async def subsribe_one(self, url, payload):
async with websockets.connect(url) as websocket:
await websocket.send(payload)
while True:
msg = await websocket.recv()
print(msg)
答案 1 :(得分:1)
这是我最终做的,这样就不会阻塞主线程,并且所有订阅都是并行工作。
def subscribe(self, payload):
ws = websocket.WebSocket(sslopt={"cert_reqs": ssl.CERT_NONE})
ws.connect(url)
ws.send(payload)
while True:
result = ws.recv()
print("Received '%s'" % result)
def start_thread(self, loop):
asyncio.set_event_loop(loop)
loop.run_forever()
def start_socket(self, **kwargs):
worker_loop = asyncio.new_event_loop()
worker = Thread(target=self.start_thread, args=(worker_loop,))
worker.start()
worker_loop.call_soon_threadsafe(self.subscribe, payload)
def listen(self):
self.start_socket(payload1)
# code
self.start_socket(payload2)
# code
self.start_socket(payload3)
答案 2 :(得分:0)
一种有效侦听来自websocket服务器的多个websocket连接的方法是保留已连接客户端的列表,并实质上并行处理多个会话。
例如一个简单的服务器,每隔几秒钟就会向每个连接的客户端随机发送#号:
import os
import asyncio
import websockets
import random
websocket_clients = set()
async def handle_socket_connection(websocket, path):
"""Handles the whole lifecycle of each client's websocket connection."""
websocket_clients.add(websocket)
print(f'New connection from: {websocket.remote_address} ({len(websocket_clients)} total)')
try:
# This loop will keep listening on the socket until its closed.
async for raw_message in websocket:
print(f'Got: [{raw_message}] from socket [{id(websocket)}]')
except websockets.exceptions.ConnectionClosedError as cce:
pass
finally:
print(f'Disconnected from socket [{id(websocket)}]...')
websocket_clients.remove(websocket)
async def broadcast_random_number(loop):
"""Keeps sending a random # to each connected websocket client"""
while True:
for c in websocket_clients:
num = str(random.randint(10, 99))
print(f'Sending [{num}] to socket [{id(c)}]')
await c.send(num)
await asyncio.sleep(2)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
try:
socket_server = websockets.serve(handle_socket_connection, 'localhost', 6789)
print(f'Started socket server: {socket_server} ...')
loop.run_until_complete(socket_server)
loop.run_until_complete(broadcast_random_number(loop))
loop.run_forever()
finally:
loop.close()
print(f"Successfully shutdown [{loop}].")
连接到服务器并监听号码的简单客户端:
import asyncio
import random
import websockets
async def handle_message():
uri = "ws://localhost:6789"
async with websockets.connect(uri) as websocket:
msg = 'Please send me a number...'
print(f'Sending [{msg}] to [{websocket}]')
await websocket.send(msg)
while True:
got_back = await websocket.recv()
print(f"Got: {got_back}")
asyncio.get_event_loop().run_until_complete(handle_message())
混合线程和asyncio
的麻烦多于其价值,并且您仍然拥有将阻塞诸如网络IO之类的最浪费步骤的代码(这是使用asyncio
的基本好处)。 / p>
您需要在事件循环中异步运行每个协程,使用await
调用任何阻塞调用,并定义与任何交互的方法与async
查看有效的示例,例如:https://github.com/adnantium/websocket_client_server