基于PyQt5的端口扫描器
由于课设的关系,选择用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)
前者发包的时候会把我写好的头当作数据发出去
后者直接报错
弄了好多小时也无解,故放弃
后来学长说python的socket库不完整。。可能是某些原因吧
二,PyQt5
这是第三个用pyqt写的程序了,然而才发现designer这个好东西,直接画界面就好了
界面的第一版不怎么好看,第二版算是正式版
想想遇到的坑吧。。
将滚动条直接滚到底部,这么一个小功能还是找了好久
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)
差不多就这些另外 推荐
图标很多,颜色随心
最后,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
可以利用信号(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日
上一篇: Masscan——端口扫描
下一篇: 端口扫描器的几种代码实现方案