栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

python命令解析使用多线程扫描端口

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

python命令解析使用多线程扫描端口

使用python实现端口扫描的脚本,使用到optparse模块解析命令
大部分解释已写入脚本注释。文件名为portscan.py

'''
命令解析,多线程,端口扫描
----------author:Bluecap-------------
'''

#命令行参数解析模块
from optparse import OptionParser
import queue
import socket
import re
import threading


parser=OptionParser('Usage: %prog -i')
#添加命令,这里可以选定类型,当然后面的正则可能没有必要
parser.add_option('-i',dest='ip',type='string',help='specify target ip')
#端口为范围,或者单个。单个单线程,多个多线程
parser.add_option('-p',dest='port',type='string',help='specify target port')
parser.add_option('--thread',dest='thread',type='int',help='specify thread num')
#接上--brief只显示开放端口,store_true为加上--brief时brief为True,否则为False
parser.add_option('--brief',dest='brief',action='store_true',help='brief mode')
#全局参数控制输出
# flag=False
#解析命令
opts,argv=parser.parse_args()
# print('opts:',opts)
# print('argv:',argv)
# print(type(opts))
# print(opts.ip)
# print(opts.port)
# print(type(opts.thread))
'''
opts: {'ip': None, 'port': None, 'thread': None}
E:python作业2>python portscan.py -i 120.0.0.1 -p 21 --thread 4
opts: {'ip': '120.0.0.1', 'port': '21', 'thread': 4}
argv: []
'''
def print_help():
    print('Usage: %prog -i -p --thread --brief')#至少要输入ip和端口


#单线程扫描 单个端口或者端口范围
def singleThread(ip,ports):
    try:
        port=int(ports)
        s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        if s.connect_ex((ip,port))==0:
            print('|{:^16}|{:^16}|{:^16}|'.format(ip,port,'开放'))
        else:
            print('|{:^16}|{:^16}|{:^16}|'.format(ip,port,'关闭'))
    except:
        pre_port=int(opts.port.split('-')[0])
        suf_port=int(opts.port.split('-')[1])
        if pre_port==suf_port:
            port=pre_port
            s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            #连接成功返回0,失败返回编码
            if s.connect_ex((ip,port))==0:
                print('|{:^16}|{:^16}|{:^16}|'.format(ip,port,'开放'))
            else:
                print('|{:^16}|{:^16}|{:^16}|'.format(ip,port,'关闭'))
        elif pre_port0 and threads<=20:
            if threads>=port_num:
                #print('多线程第一种情况')
                threads=port_num
                for t in range(threads):
                    try:
                        thread=threading.Thread(target=scanport,args=(ip,pre_port+t),daemon=True)#传递参数,设置为守护线程
                        thread.start()
                        #print(f'线程{t+1}开始启动...')
                    except threading.ThreadError as e:
                        print(f'线程{t+1}执行异常')
            else:
                #print('多线程第二种情况')
                #初始时创建四个线程
                for th in range(threads):
                    try:
                        thread=threading.Thread(target=scanport,args=(ip,queue_ports.get()))#如果设置成守护线程可能有几个端口就有几个线程
                        thread.start()
                        #print(f'线程{th+1}开始启动...')
                    except threading.ThreadError as e:
                        print(f'线程{th+1}执行异常')
                else:#执行完for后执行else
                    while True:
                        # if queue_ports.empty():
                        #     break
                        thread_number=threading.active_count()#等同于threading.enumerate()
                        surplus_ports=queue_ports.qsize()#当前未扫描端口数
                        #print('surplus_ports:',surplus_ports)
                        if surplus_ports==0:
                            break
                        #print('未扫描端口数:',surplus_ports)
                        #保证有4个进程在运行,当扫描的端口少于4个时,且线程够用,就不再增加线程
                        if thread_number<(threads+1):
                            #补齐
                            gap_thread=threads-thread_number#差的线程数
                            for i in range(gap_thread):
                                thread=threading.Thread(target=scanport,args=(ip,queue_ports.get()))
                                thread.start()
                                #print(f'当前线程数为:{len(threading.enumerate())}')

                        else:
                            #等线程结束后再增加线程
                            continue
                        
                        

                       

        else:
            print('线程数最大为20')
            exit(1)
        
        if queue_ports.empty():
            #print('扫描完成...')
            exit(1)
        




def banner():
    print('+'+'-'*50+'+')
    print('|{:^16}|{:^16}|{:^16}|'.format('ip','port','status'))
    print('+'+'-'*50+'+')

if __name__=='__main__':
    #None为python空类型
    if opts.ip is None or opts.port is None:
        print_help()
    else:
        #检查IP格式
        ip=re.match('^d{1,3}.d{1,3}.d{1,3}.d{1,3}$',opts.ip)#匹配成功返回ip,不成功返回None
        if ip is None:
            print('ip格式错误')
            exit(1)
        else:
            ip=ip.group()
            try:#检查端口格式
                port=int(opts.port)
            except:
                #端口格式报错,说明输入是端口范围
                ports=re.match('^d{1,5}-d{1,5}$',opts.port)
                if ports is None:
                    print('端口格式错误')
                    exit(1)
                else:
                    #print('端口格式正确')
                    ports=ports.group()
                    threads=opts.thread
                    #print('threads:',type(threads))
                    if threads is None:#不输入线程数默认使用单线程
                        print('单线程扫描...')
                        banner()
                        singleThread(ip,ports)
                    else:
                        if threads>0 and threads<=20:
                            print('多线程扫描...')
                            banner()
                            MultiThread(ip,ports,threads)
                            print('-'*50)
                            print('扫描完成...')
                        else:
                            print('线程数错误,最大为20')
                            exit(1)
                        
                    
            else:
                banner()
                #为单端口
                singleThread(ip,port)
    #只剩下主线程,结束程序
    if threading.enumerate()==1:
        exit(1)    



'''
使用示例:
python portscan.py -i 127.0.0.1 -p 440-500 --thread 10 --brief使用10个线程扫描,只显示开放端口
python portscan.py -i 127.0.0.1 -p 440-500 --thread 10 使用10个线程扫描,显示所有端口
python portscan.py -i 127.0.0.1 -p 440-500不加线程参数,默认使用单线程
python portscan.py -i 127.0.0.1 -p 440-440只扫描440端口
python portscan.py -i 127.0.0.1 -p 445只扫描445端口
'''

练习使用python optparse写的一个作业,粗糙还望见谅!目前还存在Bug,也暂时还找不出问题所在。有需求的大佬可以进一步更改以实现更多的功能,比如说扫描ip段。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/968645.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号