Python Tkinter学习之端口扫描器的编写

Python Tkinter之端口扫描器的编写

这其实是个作业,要求我们使用python GUI界面做一个端口扫描
不过tk之前一直没有接触过,所以记录一下!

图形化界面编写

先把图形化界面编写完成:

from tkinter import *
import socket
import threading
import time
import queue
import tkinter.messagebox as msgbox

class MyGui():
    def __init__(self, init_window_name):
        self.init_window_name = init_window_name

    def set_init_window(self):                  #初始化窗口
        self.init_window_name.title("端口扫描器 v1.0")	#定义标题
        self.window_center(400, 520)
        self.init_window_name.resizable(0,0)    #固定窗口,禁止拖拉

        # 定义区域,把全局分为上中下部分
        self.frame_top = Frame(self.init_window_name, width=400, height=200)
        self.frame_center = Frame(self.init_window_name, width=400, height=300)
        self.frame_foot = Frame(self.init_window_name, width=400, height=10)
		
        self.frame_top.grid(row=0, column=0)
        self.frame_center.grid(row=1, column=0)
        self.frame_foot.grid(row=2, column=0, pady="20")

        # 上部分布局
        self.ip_lb_top = Label(self.frame_top, text="IP地址", font="楷体")
        self.port_lb_top = Label(self.frame_top, text="端口列表", font="楷体")
        self.ip_input = StringVar()
        self.port_input = StringVar()
        self.ip_input.set('127.0.0.1')	#设置输入框默认的值
        self.port_input.set('1-65535')
        self.ip_content = Entry(self.frame_top, textvariable=self.ip_input, font="楷体")		#输入框
        self.port_content = Entry(self.frame_top, textvariable=self.port_input, font="楷体")	#输入框二
        self.PortScan = Button(self.frame_top, text="开始扫描", command=self.runing, font="楷体")	#点击按钮,执行self.runing函数
        self.sign = Label(self.frame_top, text="By A_dmin", font="楷体")
        self.ip_lb_top.grid(row=0, column=0, padx=15, pady=20)
        self.ip_content.grid(row=0, column=1, padx=15, pady=20)
        self.port_lb_top.grid(row=1, column=0, padx=15, pady=20)
        self.port_content.grid(row=1, column=1, padx=15, pady=20)
        self.PortScan.grid(row=3, column=0, padx=15, pady=20)
        self.sign.grid(row=3, column=1, padx=15, pady=20)

        # 中间部分布局
        self.porttext = Text(self.frame_center, width=48, height=22)
        self.scroll = Scrollbar(self.frame_center)		#为text添加滚动条
        self.scroll.pack(side=RIGHT, fill=Y)
        self.porttext.pack(side=RIGHT, fill=Y)
        self.scroll.config(command=self.porttext.yview)
        self.porttext.config(yscrollcommand=self.scroll.set)
        #self.porttext.grid(row=0, column=0, pady=10)

        # 下部分布局

    # 窗口居中
    def window_center(self, width, height):
        screenwidth = self.init_window_name.winfo_screenwidth()
        screenheight = self.init_window_name.winfo_screenheight()
        size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        self.init_window_name.geometry(size)

    # 获取当前时间
    def get_current_time(self):
        current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        return current_time
		
    def runing(self):
        pass

if __name__ == "__main__":
    pygui=Tk()
    init_window = MyGui(pygui)
    init_window.set_init_window()
    pygui.mainloop()

运行结果图:
在这里插入图片描述

编写功能函数

这里遇到一个重大的问题,就是程序会假死,,,,,
百度了一下原因:tk在做大量的写入时,会进入假死或无响应状态,也就是执行耗时长的操作
最后找到解决办法:继承多线程类,并且直接在初始化函数中开启线程,代码如下

class MyThread(threading.Thread):
        def __init__(self, func, *args):
            super().__init__()

            self.func = func
            self.args = args

            self.setDaemon(True)
            self.start()  # 在这里开始

        def run(self):
            self.func(*self.args)

解决了如上问题就好办了,功能函数的编写就是利用socket还有多线程,外加一个队列:

def runing(self):
        self.porttext.delete(1.0, END)
        if re.match(r"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$", self.ip_content.get()):
            self.ip = self.ip_content.get()
        else:
            msgbox.showerror(title="Error", message="ip格式错误,格式为:x.x.x.x")
            return
        if re.match(r"^(?:[0-9]{1,5}-){1}[0-9]{1,5}$", self.port_content.get()):
            ports = self.port_content.get()
        else:
            msgbox.showerror(title="Error", message="端口列表格式错误,格式为:xxx-xxx,而且必须是数字")
            return
        ports = ports.split('-')
        startport = ports[0]
        endport = ports[1]
        self.porttext.insert(END, "当前时间为: "+self.get_current_time()+"\nIP地址:"+self.ip+"\n端口列表:"+self.port_content.get()+"\n开始扫描\n")
        self.portslist = list(range(int(startport), int(endport) + 1))
        port_queue = queue.Queue()
        for port in self.portslist:
            port_queue.put(port)
        for i in range(0, 200):
            self.MyThread(self.scan, port_queue)

    def scan(self, port_queue):
        while True:
            if port_queue.empty():
                break
            ip = self.ip
            port = port_queue.get()
            timeout = 0.5

            try:
                s = socket.socket()
                s.settimeout(timeout)
                s.connect((self.ip, port))
                string = "Port " + str(port) + " is OPEN\n"
                self.porttext.insert(END, string)
                self.porttext.see(END)
            except Exception as e:
                pass
            finally:
                s.close()

综上代码就已经书写完毕了,运行结果如图:
在这里插入图片描述

整体代码以及生成exe文件

整体代码如下:

from tkinter import *
import socket
import threading
import time
import queue
import tkinter.messagebox as msgbox

class MyGui():
    def __init__(self, init_window_name):
        self.init_window_name = init_window_name

    def set_init_window(self):                  #初始化窗口
        self.init_window_name.title("端口扫描器 v1.0")
        self.window_center(400, 520)
        self.init_window_name.resizable(0,0)    #固定窗口,禁止拖拉

        # 定义区域,把全局分为上中下部分
        self.frame_top = Frame(self.init_window_name, width=400, height=200)
        self.frame_center = Frame(self.init_window_name, width=400, height=300)
        self.frame_foot = Frame(self.init_window_name, width=400, height=10)
        self.frame_top.grid(row=0, column=0)
        self.frame_center.grid(row=1, column=0)
        self.frame_foot.grid(row=2, column=0, pady="20")

        # 上部分布局
        self.ip_lb_top = Label(self.frame_top, text="IP地址", font="楷体")
        self.port_lb_top = Label(self.frame_top, text="端口列表", font="楷体")
        self.ip_input = StringVar()
        self.port_input = StringVar()
        self.ip_input.set('127.0.0.1')
        self.port_input.set('1-65535')
        self.ip_content = Entry(self.frame_top, textvariable=self.ip_input, font="楷体")
        self.port_content = Entry(self.frame_top, textvariable=self.port_input, font="楷体")
        self.PortScan = Button(self.frame_top, text="开始扫描", command=self.runing, font="楷体")
        self.sign = Label(self.frame_top, text="By A_dmin", font="楷体")
        self.ip_lb_top.grid(row=0, column=0, padx=15, pady=20)
        self.ip_content.grid(row=0, column=1, padx=15, pady=20)
        self.port_lb_top.grid(row=1, column=0, padx=15, pady=20)
        self.port_content.grid(row=1, column=1, padx=15, pady=20)
        self.PortScan.grid(row=3, column=0, padx=15, pady=20)
        self.sign.grid(row=3, column=1, padx=15, pady=20)

        # 中间部分布局
        self.porttext = Text(self.frame_center, width=48, height=22)
        self.scroll = Scrollbar(self.frame_center)
        self.scroll.pack(side=RIGHT, fill=Y)
        self.porttext.pack(side=RIGHT, fill=Y)
        self.scroll.config(command=self.porttext.yview)
        self.porttext.config(yscrollcommand=self.scroll.set)
        #self.porttext.grid(row=0, column=0, pady=10)

        # 下部分布局

    # 窗口居中
    def window_center(self, width, height):
        screenwidth = self.init_window_name.winfo_screenwidth()
        screenheight = self.init_window_name.winfo_screenheight()
        size = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
        self.init_window_name.geometry(size)

    # 获取当前时间
    def get_current_time(self):
        current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        return current_time

    class MyThread(threading.Thread):
        def __init__(self, func, *args):
            super().__init__()

            self.func = func
            self.args = args

            self.setDaemon(True)
            self.start()  # 在这里开始

        def run(self):
            self.func(*self.args)

    def runing(self):
        self.porttext.delete(1.0, END)
        if re.match(r"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$", self.ip_content.get()):
            self.ip = self.ip_content.get()
        else:
            msgbox.showerror(title="Error", message="ip格式错误,格式为:x.x.x.x")
            return
        if re.match(r"^(?:[0-9]{1,5}-){1}[0-9]{1,5}$", self.port_content.get()):
            ports = self.port_content.get()
        else:
            msgbox.showerror(title="Error", message="端口列表格式错误,格式为:xxx-xxx,而且必须是数字")
            return
        ports = ports.split('-')
        startport = ports[0]
        endport = ports[1]
        self.porttext.insert(END, "当前时间为: "+self.get_current_time()+"\nIP地址:"+self.ip+"\n端口列表:"+self.port_content.get()+"\n开始扫描\n")
        self.portslist = list(range(int(startport), int(endport) + 1))
        port_queue = queue.Queue()
        for port in self.portslist:
            port_queue.put(port)
        for i in range(0, 800):
            self.MyThread(self.scan, port_queue)

    def scan(self, port_queue):
        while True:
            if port_queue.empty():
                break
            ip = self.ip
            port = port_queue.get()
            timeout = 0.5

            try:
                s = socket.socket()
                s.settimeout(timeout)
                s.connect((self.ip, port))
                string = "Port " + str(port) + " is OPEN\n"
                self.porttext.insert(END, string)
                self.porttext.see(END)
            except Exception as e:
                pass
            finally:
                s.close()

if __name__ == "__main__":
    pygui=Tk()
    init_window = MyGui(pygui)
    init_window.set_init_window()
    pygui.mainloop()

生成exe文件我选择使用的是pyinstaller,这里在我安装pyinstaller时出现了问题!!
出现了No module named 'setuptools.build_meta'
这里使用命令对其进行更新:pip install --upgrade setuptools
随即即可安装成功了,打开cmd命令窗口
切换到py文件所在的文件夹,然后使用命令pyinstaller -F -w PortScan.py
在这里插入图片描述
之后去文件夹下的dist目录下就可以看见有个exe文件:
在这里插入图片描述
双击即可运行!!!
在这里插入图片描述
这里还有个疑问,不知道如果电脑上没有python或者python没有安装对应的模块是否还能运行,,

总结

程序算是完成了,不知道还是否存在bug,,,不过有个小问题,没有显示何时结束,,,
不过速度上还行,由于自己电脑太差不能运行过多的线程,大概只能运行800个,
个人觉得速度挺快的,,,也算好了吧,,,
总的来说收获还是很大的,对TK有了一些了解,不至于像之前一样一点都不知道
还有在这个过程中出现了很多的问题,问题解决过程中也收获了很多!!!

猜你喜欢

转载自blog.csdn.net/qq_42967398/article/details/106637924