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有了一些瞭解,不至於像之前一樣一點都不知道
還有在這個過程中出現了很多的問題,問題解決過程中也收穫了很多!!!