功能是打开本机端口,映射到指定IP的端口
场景1本机:tomcat启动8080,通过本端口工具打开80,指向到tomcat的8080。请求本机80可以不加端口
场景2远端:访问本机80,可以访问到百度IP对应的80端口。
其他功能自行发掘。
读取与保存对应配置文件 json形式存储
配置文件保存到config.txt
环境依赖 qt5需要安装
制作exe可执行文件 先安装 pip3 install pyinstaller
pyinstaller -F -i icon.ico -w xx.py
没有icon.ico图标文件的可以删了 -i 参数 pyinstaller -F -w xx.py
# -*- coding: utf-8 -*- # 制作本地可执行文件 # pyinstaller -F -i ico.ico -w port.py import sys import json import socket,threading import os import re import traceback from PyQt5 import QtWidgets,QtCore from PyQt5.QtWidgets import QApplication, QWidget, QTextBrowser, QMessageBox from PyQt5.QtGui import QIcon, QPixmap # 图标文件 iconB = b'\x00\x00\x01\x00\x01\x00 \x00\x00\x01\x00 \x00\xa8\x10\x00\x00\x16\x00\x00\x00(\x00\x00\x00 \x00\x00\x00@\x00\x00\x00\x01\x00 \x00\x00\x00\x00\x00\x00\x10\x00\x00\xc3\x0e\x00\x00\xc3\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:Od\x00;Of\x00:Of\x00:Of\x00;Of\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00:Oe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pe\x00;Pe\x00;Pf\x00;Pf\x00:Of\x02:Of\x01;Of\x00;Pf\x00;Pf\x02;Oe\x01;Pf\x00;Pf\x00;Pe\x00;Pf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pe\x00;Pe\x04;Pf";PfV:OfH;Pg\t+=P\x00.AU\x00;Pg\x0f;PfP;PfQ;Pf\x1c;Pe\x02;Pe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pf\x00;PfK;Pf\xd0Y\xc4"=Y\xc2!9P\xb1 4H\x81/BV\xa29Mb\xab@Vm\x0f5I]\x00!1B\x00(7G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 /@\x00 .>\x00\x1e\'2\x07\x1f0AY$\x00!1B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:Pf\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00 0A\x00\x1f.>\x00\x1e)6\x0c!4H\x8d%Gi\xf7(W\x85\xff)\\\x8c\xff)\\\x8c\xff)\\\x8c\xff)[\x8b\xff)[\x8b\xff)\\\x8b\xff)\\\x8c\xff)\\\x8c\xff)V\x82\xff&Fd\xef%7In!&-\x03!0?\x00\x1f0@\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pf\x00;Pf\x05;Pf5:Pf\x06:Pf\x00\x1f0A\x000c\x9a\x00!3Gu\'Lp\xfd,_\x91\xff,`\x92\xff,_\x91\xff,_\x91\xff,`\x91\xff,`\x91\xff-`\x91\xff.a\x92\xff/b\x93\xff0c\x93\xff1d\x94\xff2c\x92\xff+Kk\xf3 1BS"4H\x00\x161=\x00:Pf\x00;Pf\x0c;Pf:;Pf\x02;Pf\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pf\x00;Pf\r;Pf\x8f;Pf\x17;Of\x00 0A\x00\x1e*6\x1c%B_\xd8.a\x93\xff/e\x98\xff/d\x98\xff-a\x92\xff/c\x95\xff2g\x9a\xff3g\x99\xff4h\x9a\xff5i\x9b\xff3e\x96\xff5g\x97\xff9l\x9d\xff:l\x9d\xff5d\x90\xff$-Rx\xf45g\x98\xffT\\d\xff\xfa\xf9\xf8\xff\xf2\xf2\xf2\xffqqq\xff\xad\xad\xad\xff?CG\xffsuv\xff\x8d\x8d\x8c\xff\x98\x98\x98\xff\xff\xff\xff\xff\xd6\xd5\xd4\xff6HZ\xffBv\xa9\xff(Gf\xdf\x1c&2\x1d 0A\x00;Pf\x00;Pfz;Pf\x86;Pf\x00:Qd\x00:Rd\x009Oe\x00;Pf\x00;Pf\x00;Pf\x8b;Pf\x87;Pf\x00 0A\x00\x1d(4"+Np\xe26h\x98\xff^dk\xff\xfd\xfc\xfc\xff\xf3\xf3\xf3\xff\x86\x86\x86\xff\xce\xce\xce\xff||{\xff\xb0\xb0\xb0\xff\xa6\xa6\xa6\xff\xa8\xa8\xa8\xff\xff\xff\xff\xff\xde\xdd\xdd\xff:JZ\xffAu\xa7\xff\'C`\xc5\x19\x1e%\r#4F\x009Nd\x01;Pf\xa1;Pfv;Pf\x00;Lh\x00?At\x00;Pf];Pf\x13;Pf\x00;Pfp;Pf\xb1:Oe\x05*;N\x00\x17\x19\x1e\x08&A[\xb5;o\xa1\xff;M_\xff\xd3\xd1\xd0\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\xfc\xfc\xffYYY\xff\x96\x96\x96\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xa0\xa0\xa0\xff:Xv\xff Tj!$5Fp\'C_\xfd>k\x99\xffX\x8e\xc4\xffg\x9d\xd4\xffl\xa2\xd7\xffm\xa2\xd8\xffg\x9d\xd3\xffV\x8b\xbf\xff9d\x8f\xff%>X\xf2\'7HT>Tj$;Pf@;PfL;Pft;Pf\xe5;PfW;Pf\x1c;Pf\xc7;PfW;Pf\x00;Pf\x00;Pe\x14;Pf\xbf;Pf\x87;Pf\x1e;Pf\xa4;Pf\xd9;Pf\xdf;Pf\xe5;Qg\xdd2FZ\xe4(Jk\xfe+Sz\xff-Ps\xff6]\x85\xff;d\x8d\xff;d\x8d\xff5[\x82\xff/Rt\xff-V~\xff(Ge\xfb6J_\xe0;Pf\xdf;Pf\xe4;Pf\xdf;Pf\xd7;Pf\x96:Pf\x1b;Pf\xa0;Pf\xac;Pe\n;Pf\x00;Pe\x00;Pf\x00;PfB;Pf\xdd;Pfj;Pe\x06;Pf\x16;Pf\';PfJ f\x8e\xff8Z{\xff7]\x82\xff p\x9f\xff>p\xa0\xff-Z\x85\xff"7M\x98\x01\x00\x00\x013F[\x00:Pf\x00;Qg\x00;Pf\x00;Pf\x15;Pf\x8a:Pf\x1e;Pe\x07;Pf\x96;Pf~:Oe\x04;Pf\x00;Pf\x00%6H\x00\x19",\x18&C`\xdb4j\x9e\xff:o\xa3\xff;p\xa4\xff=r\xa5\xff>r\xa5\xff=m\x9b\xff h\x91\xffBq\x9f\xffEw\xa8\xffFx\xa9\xffHy\xa9\xffFy\xa9\xff4h\x9a\xff%A]\xb8\x00\x00\x00\x03* \x00\x00\x00\x00\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f0A\x00"4G\x00 0@\x00\x1c\'3\x18$8N\x81/Rv\xda \x00 0B\x00\x1f0A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 0A\x00 0A\x00\x1f.>\x00\x8b\xff\xff\x00\x1b%1% 1Cf% \x00 0A\x00 0A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0\x07\xff\xff\x80\x01\xff\xff\x80\x01\xff\xff\x80\x01\xff\xfe\x00\x00\x7f\xfe\x00\x00\x7f\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x80\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x01\xc0\x00\x00\x03\xfe\x00\x00\x7f\xff\x00\x00\xff' class Ui_MainWindow(QWidget): def setupUi(self,MainWindow): MainWindow.setObjectName("MainWindow") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") MainWindow.setCentralWidget(self.centralwidget) # self.setGeometry(300, 300, 300, 220) # 固定窗口大小 self.setFixedSize(360, 360) # self.setWindowTitle('端口映射') if os.path.exists('1ico.ico'): self.setWindowIcon(QIcon('ico.ico')) else: icon = QPixmap() icon.loadFromData(iconB) self.setWindowIcon(QIcon(icon)) # 标签 self.label1 = QtWidgets.QLabel(self.centralwidget) self.label1.setGeometry(QtCore.QRect(20, 20, 80, 20)) self.label2 = QtWidgets.QLabel(self.centralwidget) self.label2.setGeometry(QtCore.QRect(20, 50, 80, 20)) self.label3 = QtWidgets.QLabel(self.centralwidget) self.label3.setGeometry(QtCore.QRect(20, 80, 80, 20)) self.input1 = QtWidgets.QLineEdit(self.centralwidget) self.input1.setGeometry(QtCore.QRect(120, 20, 80, 22)) self.input1.setObjectName("input1") self.input2 = QtWidgets.QLineEdit(self.centralwidget) self.input2.setGeometry(QtCore.QRect(120, 50, 200, 22)) self.input2.setObjectName("input2") self.input3 = QtWidgets.QLineEdit(self.centralwidget) self.input3.setGeometry(QtCore.QRect(120, 80, 80, 22)) self.input3.setObjectName("input3") # 放置按钮 self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(120, 110, 80, 25)) self.stopButton = QtWidgets.QPushButton(self.centralwidget) self.stopButton.setGeometry(QtCore.QRect(220, 110, 80, 25)) self.stopButton.setEnabled(False) self.saveButton = QtWidgets.QPushButton(self.centralwidget) self.saveButton.setGeometry(QtCore.QRect(220, 20, 45, 25)) self.loadButton = QtWidgets.QPushButton(self.centralwidget) self.loadButton.setGeometry(QtCore.QRect(270, 20, 45, 25)) self.text_browser = QTextBrowser(self.centralwidget) self.text_browser.setGeometry(QtCore.QRect(20, 150, 320, 190)) self.retranslateUi(MQt) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate self.setWindowTitle(_translate("MainWindow", "端口映射")) self.label1.setText(_translate("MainWindow", "本机端口:")) self.label2.setText(_translate("MainWindow", "目标IP:")) self.label3.setText(_translate("MainWindow", "目标端口:")) self.pushButton.setText(_translate("MainWindow", "开始")) self.saveButton.setText(_translate("MainWindow", "保存")) self.loadButton.setText(_translate("MainWindow", "读取")) self.stopButton.setText(_translate("MainWindow", "停止")) class PipeThread(threading.Thread): def __init__(self, source, target): threading.Thread.__init__(self,daemon=True) self.source = source self.target = target def run(self): while True: try: data = self.source.recv(1024) if not data: break self.target.send(data) except: print("通道退出...") break # 本地与目标ip端口建立通道 sockArr = [] # 是否是运行状态 开始/停止 isRunning = True # 本地绑定端口,停止的时候需要释放本地端口 bindArr = [] class Forwarding(threading.Thread): def __init__(self, port, targethost, targetport,targetTxt): threading.Thread.__init__(self,daemon=True) self.targethost = targethost self.targetport = targetport self.targetTxt = targetTxt self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind(('0.0.0.0', port)) self.sock.listen(10) global bindArr bindArr.append(self.sock) def run(self): while True: try: client_fd, addr = self.sock.accept() except Exception as e: print("Forwarding Exception") break print("try connect...") global isRunning if not isRunning: print("停止运行") break print("connecting...") global sockArr target_fd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) target_fd.connect((self.targethost, self.targetport)) sockArr.append(client_fd) sockArr.append(target_fd) self.targetTxt.append('new connect') # two direct pipe thread_1 = PipeThread(target_fd, client_fd) thread_1.start() thread_2 = PipeThread(client_fd, target_fd) thread_2.start() print("connected") def stop(self): try: global sockArr global bindArr for sock in sockArr: print("关闭sock") sock.close() sockArr = [] except Exception as e: print("关闭线程异常") try: for bind in bindArr: print("关闭bind本地端口") bind.close() bindArr = [] except Exception as e: print("关闭bind本地端口异常") configFile = "config.txt" thread0 = None class MQt(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super(MQt,self).__init__() self.setupUi(self) self.pushButton.clicked.connect(self.run) self.saveButton.clicked.connect(self.save) self.loadButton.clicked.connect(self.load) self.stopButton.clicked.connect(self.stop) # 加载本地配置文件 self.load() def stop(self): print("stop") global isRunning isRunning = False global thread0 thread0.stop() self.pushButton.setEnabled(True) self.stopButton.setEnabled(False) self.text_browser.append("停止") def save(self): tx1 = self.input1.text().strip() tx2 = self.input2.text().strip() tx3 = self.input3.text().strip() if tx1=='' or tx2=='' or tx3=='': self.text_browser.append("保存失败:配置信息不能为空") return arr = [] arr.append(tx1) arr.append(tx2) arr.append(tx3) saveJSON = json.dumps(arr) with open(configFile,"w", encoding='UTF-8', errors="strict") as f: f.write(saveJSON) self.text_browser.append("保存成功:{}".format(saveJSON)) self.text_browser.append("文件名:{}".format(configFile)) def load(self): if os.path.exists(configFile): try: with open(configFile, 'r', encoding='UTF-8', errors="strict") as f: text = f.read() arr = json.loads(text) if len(arr)==3: self.input1.setText(arr[0]) self.input2.setText(arr[1]) self.input3.setText(arr[2]) self.text_browser.append("读取成功:{}".format(text)) else: self.text_browser.append("读取异常:{}".format(text)) self.text_browser.append("文件名:{}".format(configFile)) except Exception as e: self.text_browser.append("读取异常") self.text_browser.append("文件名:{}".format(configFile)) print("读取配置文件失败:") print(e) traceback.print_exc() else: self.text_browser.append("配置文件不存在") self.text_browser.append("文件名:{}".format(configFile)) # 定义槽函数 def run(self): print("执行了run") global isRunning try: # 获取输入框 tx1 = self.input1.text().strip() tx2 = self.input2.text().strip() tx3 = self.input3.text().strip() numRe = re.compile(r"[\d]+") ipRe = re.compile(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$") comRe = re.compile(r"[.\w-]*(:\d{,8})") if not numRe.match(tx1) or not (int(tx1)>0 and int(tx1)<65536): QMessageBox.warning(None, "错误", "本机端口需要是数字,范围是 1-65535", QMessageBox.Yes) return if not numRe.match(tx3) or not (int(tx3)>0 and int(tx3)<65536): QMessageBox.warning(None, "错误", "目标端口需要是数字,范围是 1-65535", QMessageBox.Yes) return if not (comRe.match(tx2) or ipRe.match(tx2)): QMessageBox.warning(None, "错误", "目标IP格式异常。", QMessageBox.Yes ) return # 校验完成 print('Starting...') port = int(tx1) targethost = tx2 targetport = int(tx3) print('localhost:{} => {}:{}'.format(port,targethost,targetport)) self.text_browser.setText('localhost:{} => {}:{}'.format(port,targethost,targetport)) # sys.stdout = open('forwaring.log', 'w') self.pushButton.setEnabled(False) self.stopButton.setEnabled(True) global thread0 thread0 = Forwarding(port, targethost, targetport,self.text_browser) thread0.start() isRunning = True except Exception as e: isRunning = False self.pushButton.setEnabled(True) self.stopButton.setEnabled(False) print("失败:") print(e) traceback.print_exc() if __name__ == '__main__': app = QApplication(sys.argv) win = MQt() win.show() sys.exit(app.exec_())
到此这篇关于python3 QT5 端口转发工具的文章就介绍到这了,更多相关python3 QT5 端口转发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!