2017-05-26 140 views
2

我正在使用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

回答

2

你可以通過簡單地在一個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(主機,端口),並沒有引發異常。 –