本章目标
利用PySide2的信号和槽,在点击了GUI上的“启动”按钮后:
1、从界面上获得各项输入的参数数据
2、对参数进行转换和输出
3、进行合理范围判断,对于异常的数据进行弹窗处理
步骤实施
首先引入 Slot 模块,学过vue的话知道这个叫 插槽 。
from PySide2.QtCore import Slot # 插槽模块
然后创建槽函数,用来接受点击了“启动”按钮后传过来的数据:
@Slot()
def collect_data():
print('clicked')
其中 “@Slot”是装饰器,表明这是一个槽函数。
接下来是建立连接:
start_btn = QPushButton() # 修改父类
start_btn.setText('启动')
start_btn.clicked.connect(collect_data) # 建立连接
测试一下,运行界面,然后点一下启动按钮,看看有没有输出:
很好,成功了。
这样就开始试着去调用各个控件去输出数据:
@Slot()
def collect_data():
print(ip_line_edit.text())
print(type(ip_line_edit.text()))
print(thread_line_edit.text())
print(type(thread_line_edit.text()))
print(port_line_edit1.text())
print(type(port_line_edit1.text()))
print(port_line_edit2.text())
print(type(port_line_edit2.text()))
打印获得的数据,和判断一下类型:
127.0.0.1
<class 'str'>
500
<class 'str'>
0
<class 'str'>
65535
<class 'str'>
成功接收到数据,那接下来开始做数据清洗的动作:
MESSAGE = (
'ip或者网址不得为空',
'并发数不得小于1',
'开始端口号不得小于0',
'结束端口号需要大于开始端口号'
)
def show_tip(message): # 遇到问题,则丢到这里,抛到界面上
tip = QMessageBox(window)
tip.setWindowTitle('提示')
tip.setText(message)
tip.show()
@Slot()
def collect_data():
ip = ip_line_edit.text()
thread_line = int(thread_line_edit.text())
port_start = int(port_line_edit1.text())
port_end = int(port_line_edit2.text())
if not ip:
show_tip(MESSAGE[0])
return
if thread_line < 1:
show_tip(MESSAGE[1])
return
if port_start < 0:
show_tip(MESSAGE[2])
return
if port_end <= port_start:
show_tip(MESSAGE[3])
return
# TODO
# 调用逻辑代码
这里又引入了QMessageBox模块,用于错误信息弹窗。
测试了下各种情况,符合预期,继续下一步,封装之前写好的逻辑代码,方便调用:
PortSearch.py的代码
# coding=utf-8
import socket
import threading
class PortSearch:
def __init__(self, ip='', thread_line=500, port_start=0, port_end=65535):
self.global_list = [] # 收集开着的端口信息
self.global_err_list = [] # 收集关着的端口信息
self.global_thread_list = [] # 线程收集列表
self.lock = threading.Lock() # 创建一个锁
self.sem = threading.Semaphore(thread_line) # 并发500
self.ip = ip
self.port_start = port_start
self.port_end = port_end
def port_search(self, _ip, _port):
address = (_ip, _port) # 地址必须是一个元祖,第一个是str,第二个是int
client = socket.socket() # 创建套接字
code = client.connect_ex(address)
self.lock.acquire()
try:
if code == 0: # 当端口开启时,错误码是0,其他错误码均表示未开该端口
self.global_list.append([_ip, _port, code, client.recv(1024)])
else:
self.global_err_list.append([_ip, _port, code]) # 此处不能调用 recv api,会抛出异常
except BaseException:
print('进行列表操作时报错')
self.lock.release()
client.close() # 关闭连接
def run(self):
for i in range(self.port_start, self.port_end+1): # 0~65535
with self.sem:
thread = threading.Thread(target=self.port_search, args=(self.ip, i))
self.global_thread_list.append(thread)
thread.start()
for t in self.global_thread_list: # 遍历,等待所有进程运行完毕
t.join()
return self.global_list
继续修改PortSearchGUI.py的代码,引入逻辑代码:
from PortSearch import PortSearch
import json
在槽函数里调用:
search = PortSearch(ip=ip, thread_line=thread_line, port_start=port_start, port_end=port_end)
result = search.run()
type(result)
print(result)
# string = json.dumps(result)
# report_box_edit.setPlainText(string)
结语
试运行,能出结果,还有一些问题待优化,比如点击按钮之后工具会卡住,结果还不能输出到大编辑框内。
这些问题都留到下个篇章处理。
今天的目标已经达到,而且超出。下个篇章主要做一些优化方面的事情,使得工具更好用。