这其实是个作业,要求我们使用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()
整体代码如下:
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有了一些了解,不至于像之前一样一点都不知道
还有在这个过程中出现了很多的问题,问题解决过程中也收获了很多!!!