如何处理TCP客户端套接字在python asyncio中自动重新连接?

问题描述:

我正在使用python asyncio流连接到多个套接字服务器,但是当服务器关闭时,我的代码无法自动重新连接。如何处理TCP客户端套接字在python asyncio中自动重新连接?

我需要的是,当服务器关闭时,我的脚本会尝试每5秒重新连接,直到连接并开始再次解析数据。

import asyncio 

server1 = {'host': '192.168.1.51', 'port': 11110} 
server2 = {'host': '192.168.1.52', 'port': 11110} 


async def tcp_client(host, port, loop): 
    print('connect to server {} {}'.format(host, str(port))) 
    reader, writer = await asyncio.open_connection(host, port, loop=loop) 

    while True: 
     data = await reader.read(100) 
     print('raw data received: {}'.format(data)) 

     await asyncio.sleep(0.1) 


loop = asyncio.get_event_loop() 
try: 
    for server in [server1, server2]: 
     loop.run_until_complete(tcp_client(server['host'], server['port'], loop)) 
     print('task added: connect to server {} {}'.format(server['host'], server['port'])) 
finally: 
    loop.close() 
    print('loop closed') 
+0

第一:你不能在使用点符号词典访问项目 - 使用'服务器[“主机”]'或'服务器。获得( '主机')'。 – mhawke

+1

另一个问题是'loop.run_until_complete()'运行直到它完成,即它阻塞。因此,一次只能连接一台服务器。 – mhawke

+0

另一个问题是'tcp_client()'需要检查连接是否关闭。你可以知道当'data'是空字符串时 - 然后从函数返回。 – mhawke

你可以通过简单地在一个try/except声明循环处理重新连接。另外,asyncio.wait_for可用于设置读取操作的超时。

考虑这个工作的例子:

的所有代码将无法运行
import asyncio 

async def tcp_client(host, port): 
    reader, writer = await asyncio.open_connection(host, port) 
    try: 
     while not reader.at_eof(): 
      data = await asyncio.wait_for(reader.read(100), 3.0) 
      print('raw data received: {}'.format(data)) 
    finally: 
     writer.close() 

async def tcp_reconnect(host, port): 
    server = '{} {}'.format(host, port) 
    while True: 
     print('Connecting to server {} ...'.format(server)) 
     try: 
      await tcp_client(host, port) 
     except ConnectionRefusedError: 
      print('Connection to server {} failed!'.format(server)) 
     except asyncio.TimeoutError: 
      print('Connection to server {} timed out!'.format(server)) 
     else: 
      print('Connection to server {} is closed.'.format(server)) 
     await asyncio.sleep(2.0) 

async def main(): 
    servers = [('localhost', 8888), ('localhost', 9999)] 
    coros = [tcp_reconnect(host, port) for host, port in servers] 
    await asyncio.gather(*coros) 

if __name__ == '__main__': 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(main()) 
    loop.close() 
+0

我用你的代码但失败了。当我拔掉我的服务器并再次插入它们时,连接不会再次重新启动。以下是日志:2017-05-26 21:39:54,239 - 连接到服务器10.0.1.68 1100 ... 2017-05-26 21:39:54,240 - 连接到服务器10.0.1.69 1100 ... 2017 -05-26 21:39:54,977 - 收到的原始数据:b'030 1495834968 00.000 00.004 00.010 00.007 00.004 00.000 00.000 00.000 \ n' –

+0

@DesmondChen当您拔下服务器时可能会引发另一个异常,您可以尝试替换'ConnectionRefusedError ''例外''。另外,使用'await asyncio.gather(* coros)'会导致程序在第一个意外的异常停止。 – Vincent

+0

我将“ConnectionRefusedError异常”和“等待asyncio.wait(coros)”更改为“await asyncio.gather(* coros)”。但它仍然不起作用。我认为它卡在异步def tcp_client(主机,端口),并没有引发异常。 –