1

嗨,我有一个脚本可以保持我设备的端口状态,这是简化版本。

当连接成功(设备存在)时,我关闭连接,连接状态变为 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   - 
4

1 回答 1

0

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

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

TIME_WAIT 表示本地端点(这边)已经关闭了连接。连接被保留,以便任何延迟的数据包都可以与连接匹配并得到适当的处理。连接将在四分钟内超时时被删除。

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

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


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


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

sem = asyncio.Semaphore(100)

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

您还可以阅读此答案以查看使用信号量的真实示例。


接下来您可能需要解决的问题是您如何处理CancelledError

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

这不是任务应对此异常的方式。它永远不应该压制它,只有外部代码才能做到。阅读此答案以了解如何操作。


except:
    response = False

你从不做这种事。请阅读本主题以了解详细信息。

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

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
于 2019-03-08T17:32:13.523 回答