欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于PyQt5的端口扫描器

程序员文章站 2022-05-15 22:10:22
...

由于课设的关系,选择用PyQt5制作一个端口扫描器。期间遇到了许多问题,在此回忆总结一下

操作系统:Windows 10 1709

python版本:python 3.5.3

注:本文所述方法大部分为摸索制作过程中搜索总结而来,本文只是进行归纳汇总

一,Python-socket

判断一个端口是否开放的方法有很多,最简单的自然是建立TCP三次握手,也就是简单的connect

s = socket(AF_INET,SOCK_STREAM)
s.connect((self.host,self.port))
s.close()

用try包裹一下,做一下错误判定

except timeout:#超时,一般就认为端口为关闭,如果超时时间设置过小可能会造成遗漏
      s.close()
      return
except ConnectionRefusedError:#连接被拒绝
      s.close()
      return
except OSError as e:#其它的一些错误,当端口为0的时候会触发,还有就是linux系统中连接有上限,过了上限会报【OSERROR ERROR 24】
      if self.port!=0:
           print("OSError",self.port,self.host,e)
      return
except Exception as e:#防患于未然
      print(repr(e),self.port,self.host)
      return
本来还想尝试一下raw_socket,只建立TCP第一次握手,发SYN包,但是遇到了一些问题

raw_socket需要手动制作TCP头部和IP头部

tcp_header=Create_TCP_SYN_Header("10.241.65.141","10.241.65.1",22)
ip_header=CreateIPHeaders("10.241.65.141","10.241.65.1")
具体实现可以百度,有很多

然后就是建立这个RAW_SOCKET,一定要用管理员权限

网上有两种写法

s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
前者发包的时候会把我写好的头当作数据发出去基于PyQt5的端口扫描器

基于PyQt5的端口扫描器

后者直接报错

基于PyQt5的端口扫描器

弄了好多小时也无解,故放弃

后来学长说python的socket库不完整。。可能是某些原因吧


二,PyQt5

这是第三个用pyqt写的程序了,然而才发现designer这个好东西,直接画界面就好了

界面的第一版不怎么好看,第二版算是正式版

基于PyQt5的端口扫描器

想想遇到的坑吧。。

将滚动条直接滚到底部,这么一个小功能还是找了好久

self.listView.verticalScrollBar().setValue(self.listView.verticalScrollBar().maximum())
设置文本输入格式和范围,网上有其它类型的

self.lineEdit.setValidator(QtGui.QIntValidator(1,50000))
一组按钮可以设置号每个按钮的id,然后获取选择id来实时获取当前选项

self.buttonGroup.setId(self.ip_radio,1)
self.buttonGroup.setId(self.port_radio,0)
if self.buttonGroup.checkedId():
    self.list_by_ip()
else:
    self.list_by_port()
设置QTreeWidget宽度

self.result_tree.setColumnWidth(0,250)#第一列设成250
从QlistWidget移除选中的一行(self.ippool为QlistWidget)

self.ippool.removeItemWidget(self.ippool.takeItem(self.ippool.row(self.ippool.selectedItems()[0])))
QTreeWidgetItem设置复选框
temp=QtWidgets.QTreeWidgetItem(self.result_tree.topLevelItem(item))
temp.setFlags(temp.flags() | Qt.ItemIsUserCheckable)
temp.setCheckState(0, Qt.Unchecked)
隐藏一个QTreeWidgetItem

self.item.setHidden(True)

差不多就这些

另外 推荐

Iconfont-阿里巴巴矢量图标库

图标很多,颜色随心

最后,pyqt5的打包使用python 3.6.4 pyinstaller在windows10 32位 的虚拟机中直接打包的,直接

pyinstaller -F -w -i scan.ico scanner.py
就可以,python3.5下的pyinstaller打包不全PyQt5,32位则是希望打包后的文件可以在32和64位系统中运行

图片要转成py文件,经过引用后自动打包,图片打包成py的方法可以看我转的另一篇博客


三,线程

端口扫描器肯定是要多线程的啦

这次设计的是主界面按下按钮后,开启一个Qthread进行创建子线程操作,循环创建,设定同时运行的线程数上限,利用一些信号支持用户的手动停止

期间的问题就是,如果Qthread在执行的过程中更改了主线程的属性或内容,会造成python的不稳定,很容易直接崩溃并且无任何明显报错,唯一出现的可能是

QWidget::repaint: Recursive repaint detected

这句报错只有在控制台窗口下才会出现,IDLE并不会打印

可以利用信号(pysignal)或者其它机制避免Qthread更改主线程的属性或内容

PS:这里的不稳定十分的玄学,在某些时候直接崩溃,IDLE无任何报错,即使全部用try包裹也没用。甚至一些print语句也会影响到其崩溃是否发生,总之感觉程序处于一种极其不稳定的状态,所以据说好像QT作者并不推荐Qthread

pps:好像在IDLE下不那么容易崩溃


另外,python自带的threading不会有这个问题,不过得用好线程锁,这里就不细说了



四,总结

总之,花了总共近50个小时写出这么个东西,编程收获是要大于实际使用意义的

各种线程直接的处理,信息传递,python的内存释放机制,raw_socket尝试,啧啧

以后写个小程序出来用也会变得容易许多

文件代码扔到百度云了,有空再去传github吧

链接:https://pan.baidu.com/s/1eS2IkIe 密码:3wq2




以上,更新于2018年1月2日