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

项目需求

代码检测某个端口是否被占用,从而找出多个连续空闲的端口,由于需要 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 -tnpl
Proto 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 sys
import os
import socket


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


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

def 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, startPort


def findPort(startPort):
    while True:
        flag, endPort = checkNinePort(startPort)
        if (flag == True):  #ninePort is ok
            break
        else:
            startPort = endPort + 1
    return startPort


def 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 os
import platform
import sys


def 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 portIsUse

def 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 portIsUse

def 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, startPort


def findPort(startPort):
    while True:
        flag, endPort = checkNinePort(startPort)
        if (flag == True):  # ninePort is ok
            break
        else:
            startPort = endPort + 1
    return startPort


def main(startPort):
    firstPort=findPort(startPort)
    print 'First port of nine free ports is ', firstPort

if __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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值