写在前面:初稿写了一半停电了,啥都没了,也没心情搁那铺垫了。。。
总之,端口扫描器本身代码很简单,但是涉及了好多个面试重点关注的技术:python多线程,socket编程,tkinter图形化编程,正则表达式
以下是会用到的库,由于是标准库,在内网环境也完全可以使用

1
2
3
4
5
from tkinter import *
import tkinter.messagebox
from socket import *
from threading import Thread,Lock
import sys,re

需求:输入ip,返回该ip一些端口的开放状态
那就要判断输入是否合法,IP需要的是*.*.*.*的形式,其中*代表数字

1
2
3
4
5
6
7
8
9
10
def Judgement_IP(self):
reg = '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
ip = re.match(reg, self.IP.get())
if ip is not None:
action(ip.group())
Port_open_content = Label(self.init_window_name, text = Port_is_open)
Port_open_content.grid(row = 4, column = 1)
else:
print("IP格式错误")
tkinter.messagebox.showerror('错误', 'IP格式错误')

写tkinter窗体时用到的方法:
title(): 设置窗体的名称
self.init_window_name.title('简单端口扫描工具')
geometry(): 设置窗体大小,四个值的顺序是:宽、高、位置x, y
self.init_window_name.geometry('300x600+150+150')
iconbitmap(): 设置窗体的图标
self.init_window_name.iconbitmap('icon.ico')
Label: 组件,用于在指定的窗口中显示文本和图像
label = Label(self.init_window_name, text="IP:", anchor='c').grid(row=0)
Entry:组件,文本框用来让用户输入一行文本字符串
self.IP = Entry(self.init_window_name)
self.IP.gird(row = 0, column = 1)

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from tkinter import *
import tkinter.messagebox
from socket import *
from threading import Thread, Lock
import sys, re

Port_is_open = ''

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

def set_init_window(self):
self.init_window_name.title('简单的端口扫描工具') #设置窗体的名称
self.init_window_name.geometry('300x600+150+150') #设置窗体大小,四个值的顺序是:宽、高、位置x, y
self.init_window_name.iconbitmap('icon.ico') #设置窗体的图标
#设置输入框Entry
label = Label(self.init_window_name, text="IP:", anchor='c').grid(row=0)
self.IP = Entry(self.init_window_name)
self.IP.grid(row=0, column=1)
#设置扫描按钮
Button(self.init_window_name, text="开始扫描", anchor='c', command=self.Judgment_IP).grid(row=0, column=2)

def Judgment_IP(self):
#判断输入的IP是否正确
reg = '^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
ip = re.match(reg, self.IP.get())
if ip is not None:
action(ip.group())
Port_open_content = Label(self.init_window_name, text=Port_is_open)
Port_open_content.grid(row=4,column=1)
else:
print("IP格式错误")
tkinter.messagebox.showerror('错误', 'IP格式错误')

class mythread(Thread):
def __init__(self, fun, args):
Thread.__init__(self)
self.fun = fun
self.args = args

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

def action(ip):
def scan(h, p):
global Port_is_open
try:
tcpCliSock = socket(AF_INET, SOCK_STREAM) #初始化socket,AF_INET表示IPv4 socket, SOCK_STREAM表示tcp socket,初始化了一个使用IPv4, TCP协议的socket
tcpCliSock.connect((host, p))
if lock.acquire():
Port_is_open += "" + str(p) + " -> opened\n"
lock.release()
except error:
if lock.acquire():
Port_is_open += "" + str(p) + " -> not open\n"
lock.release()
finally:
tcpCliSock.close()
del tcpCliSock

lock = Lock()
ports = [21, 22, 23, 25, 53, 69, 80, 135, 137, 139, 1521, 1433, 3306, 3389, 6371, 7001]
host = ip
mt = []
for p in ports:
t = mythread(scan,(host,p))
mt.append(t)
for m in mt:
m.start()
for m in mt:
m.join()

print(Port_is_open)

if __name__ == '__main__':
init_window = Tk()
scan = Port_Scan(init_window)
scan.set_init_window()
init_window.mainloop()

执行结果: