python-3.x - Asyncio 关闭连接使连接处于 TIME_WAIT 状态

标签 python-3.x tcp python-asyncio time-wait

您好,我有一个脚本可以保存我设备的池端口状态,这是简化版。

当连接成功(设备存在)时,我关闭连接,连接状态变为 TIME_WAIT。按时此连接起球并达到操作系统允许的最大连接数(如果我没记错的话)

不知道我应该修复哪一部分,例如我使用端口 53,但在实际应用程序上我检查多个端口,如 ssh、vnc 等。

我使用 python 3.5.6 在 ubuntu 18.04 上运行脚本

import asyncio
import ipaddress
import sys

async def check_port(ip, port, timeout=1):
    conn = None
    response = False
    writer = None

    try:
        conn = asyncio.open_connection(ip, port)
        reader, writer = await asyncio.wait_for(conn, timeout=timeout)
        response = True
    except asyncio.CancelledError:
        print("asyncio cancel")
    except:
        response = False
    finally:
        if writer is not None:
            writer.close()
        if conn is not None:
            conn.close()
        print("Closing connection {}:{}".format(ip, port))

    print("{}:{} {}".format(ip, port, response))

async def poll_status():
    ips = [str(ip) for ip in ipaddress.IPv4Network("192.168.1.0/24")]
    while True:
        try:
            tasks = [check_port(ip, 53) for ip in ips]
            await asyncio.wait(tasks)
        except asyncio.CancelledError:
            break
        except KeyboardInterrupt:
            break
        except:
            pass
        await asyncio.sleep(1)

async def shutdown(task):
    task.cancel()
    await task
    await asyncio.sleep(1)

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    task = asyncio.ensure_future(poll_status())
    try:
        loop.run_forever()
    except:
        pass
    finally:
        loop.run_until_complete(asyncio.wait([shutdown(task)]))
        loop.close()

连接一直像这样堆积(来自“netstat -nput | grep TIME_WAIT”的输出) 192.168.1.1 是我的路由器,所以它在检查端口时成功但留下了很多未关闭的连接。删除连接需要很长时间

tcp        0      0 192.168.1.4:42102       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:42582       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:46560       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:39428       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:45806       192.168.1.1:53          TIME_WAIT   -                                     
tcp        0      0 192.168.1.4:44752       192.168.1.1:53          TIME_WAIT   -                                      
tcp        0      0 192.168.1.4:40726       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:49864       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:38812       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:48464       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:41372       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:43408       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:47360       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:45478       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:41904       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:40160       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:46196       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:48744       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:49554       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:47774       192.168.1.1:53          TIME_WAIT   -                   
tcp        0      0 192.168.1.4:39370       192.168.1.1:53          TIME_WAIT   -                                    
tcp        0      0 192.168.1.4:43994       192.168.1.1:53          TIME_WAIT   - 

最佳答案

我不是网络方面的专家,不确定这个答案是否有帮助,但这是我的两分钱。

关于 netstat 输出的第一件事。它与路由器相关,似乎与您的操作系统限制无关。快速谷歌搜索 shows以下:

TIME_WAIT indicates that local endpoint (this side) has closed the connection. The connection is being kept around so that any delayed packets can be matched to the connection and handled appropriately. The connections will be removed when they time out within four minutes.

似乎是您的代码关闭了连接,即一切正常。

但是我不知道路由器将如何处理越来越多的此类连接。


现在让我们考虑您的代码。


您在 asyncio.wait(tasks) 行所做的是并行运行所有检查。根据 ips 的数量,它可能太多了。您很有可能会受益于使用 asyncio.Semaphore限制并行检查的最大数量。它看起来如下:

sem = asyncio.Semaphore(100)

async def check_port(ip, port, timeout=1):
    async with sem:
        # main code here

您还可以阅读 this answer查看使用信号量的真实示例。


接下来您可能需要修复的是如何处理 CancelledError:

except asyncio.CancelledError:
    print("asyncio cancel")

这不是任务应对此异常使用react的方式。它永远不应该压制它,只有外部代码可以做到。阅读this answer看看怎么做。


except:
    response = False

你永远不会做这样的事情。请阅读this topic了解详情。

您至少应该执行以下操作:

except Exception as exc:    # catch Exception or it's subclasses only
    logging.exception(exc)  # log for purpose not to miss exception you can fix
    response = False

关于python-3.x - Asyncio 关闭连接使连接处于 TIME_WAIT 状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55063606/

相关文章:

c++ - 如何在 C++ 中使用 recv 或 read 函数从 tcp 套接字读取大请求?

python - 有没有办法直接在Jupyter cell中调用await?

android - 无法通过 adb TCP/IP 连接 android 设备

python-3.x - 将变量写入文件

python - 如何让程序回到 "menu"?

python - 如何在Python中对月份列进行排序后找到平均值

java - 异步 TCP 连接

python - 在 python3 asyncio 中使用串口

Python 3 : How to submit an async function to a threadPool?

python - 基于匹配列值压缩数据帧