Python找出多个连续的空闲端口

来源:互联网 发布:喜马拉雅网络无法连接 编辑:程序博客网 时间:2024/05/21 16:58

项目需求

代码检测某个端口是否被占用,从而找出多个连续空闲的端口,由于需要 Windows、Linux 都能运行,所以选择了 Python,而不是 shell。

实现方案

Python 的 socket 模块

思路是 try 尝试连接某个端口,如果能连接上,表示端口被占用,否则端口空闲。

def isInuse(ipList, port):    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    flag=True    for ip in ipList:        try:            s.connect((ip, int(port)))            s.shutdown(2)            print '%d is inuse' % port            flag=True            break        except:            print '%d is free' % port            flag=False    return flag

try 模块中 如果 s.connect((ip, int(port))) 如果能成功, 说明端口被占用.

否则, connect 不成功, 会进到except 中, 说明端口不被占用.

存在问题

netstat -tnplProto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name           tcp        0      0 0.0.0.0:8080                0.0.0.0:*                   LISTEN      11563/java                      tcp        0      0 127.0.0.1:8005              0.0.0.0:*                   LISTEN      11563/java                    

源 ip 、源端口 + 目的 ip、目的端口 可以确定一条 tcp 连接。

本来以为 s.connect((ip, int(port))) ,只需要检测 "127.0.0.1","0.0.0.0"

后来发现还有可能是局域网ip 如 10.170.70.87 等等

可以通过这个方法根据远程 hostname 获得其 ip

def getLocalIp():    localIP = socket.gethostbyname(socket.gethostname())    return localIP

代码

从某个端口 port 开始,进行检测,port + 1、port + 2 … ,如果连续的空闲端口数目达到需求的 N,则 port ~ port + N 为需求的端口。

如果中途某个 port + L 端口被占用,那么从新的端口 port + L + 1 开始寻找。

本代码只针对 ipList = ("127.0.0.1","0.0.0.0",getLocalIp()) 这3个 ip 进行 connect

import sysimport osimport socketdef isInuse(ipList, port):    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    flag=True    for ip in ipList:        try:            s.connect((ip, int(port)))            s.shutdown(2)            print '%d is inuse' % port            flag=True            break        except:            print '%d is free' % port            flag=False    return flagdef getLocalIp():    localIP = socket.gethostbyname(socket.gethostname())    return localIPdef checkNinePort(startPort):    flag = True    ipList = ("127.0.0.1","0.0.0.0",getLocalIp())    for i in range(1, 10):        if (isInuse(ipList, startPort)):            flag = False            break        else:            startPort = startPort + 1    return flag, startPortdef findPort(startPort):    while True:        flag, endPort = checkNinePort(startPort)        if (flag == True):  #ninePort is ok            break        else:            startPort = endPort + 1    return startPortdef main():    startPort=51988    # startPort = int(sys.argv[1])    print findPort(startPort)main()

字符串匹配

第一种方法的准确性依赖于 connect((ip, int(port))) 中的 ip,

到底怎样的 ip 集合才是完备的, 可以确定这个端口不被占用?

思路

**在 linux 用 netstat -tnpl 可以得到端口监听信息,

观察 tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 11563/java

出现了 0 0.0.0.0:8080 所以 8080端口是被占用的


对这些输出的字符信息进行搜索 :8080, 如果存在, 就表示 8080 端口是LISTEN.

如果输出结果中不存在 :8080 的相关字符,表示这个端口不被占用.

代码

WINDOWS、 LINUX 这几个平台查看端口信息的方式不同,

先进行机器平台的判断,然后调用各个平台的端口占用判断函数

因为需求是找出连续的空闲端口,当中途只要有一个端口占用, 就跳出循环

import osimport platformimport sysdef isInuseWindow(port):    if os.popen('netstat -an | findstr :' + str(port)).readlines():        portIsUse = True        print '%d is inuse' % port    else:        portIsUse = False        print '%d is free' % port    return portIsUsedef isInuseLinux(port):    #lsof -i:8080    #not show pid to avoid complex    if os.popen('netstat -na | grep :' + str(port)).readlines():        portIsUse = True        print '%d is inuse' % port    else:        portIsUse = False        print '%d is free' % port    return portIsUsedef choosePlatform():    #'Windows-7-6.1.7601-SP1'    #'linux-2.6.32-431.23.3.el6.x86_64-x86_64-with-centos-6.5-final'    machine = platform.platform().lower()    if 'windows-' in machine:        return isInuseWindow    elif 'linux-' in machine:        return isInuseLinux    else:        print 'Error, sorry, platform is unknown'        exit(-1)def checkNinePort(startPort):    isInuseFun = choosePlatform()    nineIsFree = True    for i in range(1, 10):        if (isInuseFun(startPort)):            nineIsFree = False            break        else:            startPort = startPort + 1    return nineIsFree, startPortdef findPort(startPort):    while True:        flag, endPort = checkNinePort(startPort)        if (flag == True):  # ninePort is ok            break        else:            startPort = endPort + 1    return startPortdef main(startPort):    firstPort=findPort(startPort)    print 'First port of nine free ports is ', firstPortif __name__ == '__main__' :    if len(sys.argv) > 1:        print len(sys.argv)        startPort = int(sys.argv[1])    else:        startPort = 500    main(startPort)

相关知识点总结

os.popen()

可以调用系统的一些shell命令

os.popen().readlines()

读取调用shell命令后的回显信息

 netstat -tnpl -tnpl 各个参数的含义-l或--listening   显示监控中的服务器的Socket-n或--numeric   直接使用IP地址,而不通过域名服务器。-p或--programs   显示正在使用Socket的程序识别码和程序名称。-t或--tcp   显示TCP传输协议的连线状况----------tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN      9890/nginx   最后的9890/nginx   表示 进程号 54849 进程名 nginx   
0 0