python3 QT5 端口转发工具两种场景分析

作者:firseve 时间:2023-04-03 10:34:46 

功能是打开本机端口,映射到指定IP的端口

场景1本机:tomcat启动8080,通过本端口工具打开80,指向到tomcat的8080。请求本机80可以不加端口

场景2远端:访问本机80,可以访问到百度IP对应的80端口。

其他功能自行发掘。

python3 QT5 端口转发工具两种场景分析

读取与保存对应配置文件 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\xd0<Qgo<Od\x12\x19\x16\x15\x05\x1d#+\r\x1d")\x0c\x1a\x17\x16\x04=Qf\x18;Qg\x80;Pf\xcc;Pf1;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 0A\x003FZ\x00=Si\x1d8La\xbc-?R\x94 4I\x89!9R\xb5">Y\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$<U\xd4%Gi\xff&Py\xff&T\x80\xff\'W\x84\xff\'V\x84\xff&T\x7f\xff%Ow\xff%Ff\xff#;R\xc5\x1f/?G\x1e\x1d \x02!/>\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$<U\xb9\x1b"*\n 0@\x00;Pf\x00;Pf";Pf\x98;Pf\x07;Pf\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pf\x00;Pf\t;Pf\x9c;Pf#;Pf\x00 0A\x00\x1f,;@)Mp\xf53k\x9f\xff0c\x94\xff$B^\xff3CR\xff-AS\xff(Os\xff9n\xa0\xff7i\x98\xff(Gd\xff4DS\xff1BS\xff,Op\xff@r\xa1\xff<o\xa0\xff\'Ec\xe0\x1d(3\x1d 0A\x00;Pf\x00;Pf9;Pf\xa4;Pf\x06;Pf\x00\x00\x00\x00\x00\x00\x00\x00\x00;Pf\x00;Pf\x06;Pf\xa8;Pf=;Pf\x00 0A\x00\x1f-<G+Ot\xf98o\xa4\xff*D]\xff\x98\x98\x98\xff\xe5\xe5\xe4\xff\xd4\xd3\xd2\xffhlo\xff*Kk\xff-D[\xff\x8f\x90\x90\xff\xe0\xdf\xdf\xff\xdc\xdb\xda\xffknq\xff4Wy\xffBv\xa8\xff(Hg\xe1\x1d\'3\x1e 0A\x00;Pf\x00;PfT;Pf\x9b8Ne\x01:Of\x00\x00\x00\x00\x00;Pf\x00;Pf\x00:Pe\x03;Pf\xa7;Pf^;Pf\x00 0A\x00\x1e,:>-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<m\x9d\xff#8O\x8eE\x92\xd8\x009Mc\x00;Pf\x0f;Pf\xc4;PfR;Pf\x00;Pf\x1e;PfN;Pf\x97;PfJ;Pf\x00;PfH;Pf\xd1;Pf\x1b;Pf\x00#7L\x00 2D`5`\x8b\xfc=j\x96\xffNW`\xff\xb9\xb8\xb8\xff\xd9\xd8\xd7\xff\x8a\x8b\x8c\xff2H]\xffAP]\xff\xaf\xae\xae\xff\xda\xd9\xd8\xff\x9c\x9c\x9c\xffARb\xffJ}\xaf\xff/Uz\xef\x1f-<= 1B\x00;Pf\x00;Pf-;Pf\xd6;Pf1;Pf\x00;Pfb;Pf\x80;Pf`;Pf\x99:Od\x02;Pf#;Pf\xd9;PfE;Pf\x00\x1f/?\x00\x1b$.\x10\'A[\xb6Bw\xab\xffK{\xa9\xff?[v\xffDZp\xffCd\x85\xff_\x91\xc2\xffX\x86\xb3\xffB]x\xffF\\q\xffEd\x82\xffW\x8a\xbb\xff=m\x9c\xff#:P\x93\x15\x16\x18\x04\x1f.?\x00;Pf\x00;Pf_;Pf\xce;Oe\x13:Pf\x0b;Pf\xa8;PfF;Pf\x1a;Pf\xbb;PfD;Pf\x05;Pf\xbc;Pf\x88;Pf\x00;Pf\x00/BV\x00\x1c*8-*Ih\xd1H~\xb3\xffb\x9a\xd1\xffh\x9c\xd0\xffk\x9f\xd3\xffk\x9e\xd1\xffl\x9f\xd3\xffm\xa1\xd3\xffl\x9f\xd2\xffe\x9c\xd2\xffCt\xa5\xff&@Z\xb9\x1a$1\x181DX\x00;Pf\x00;Oj\x00;Pf\xa3;Pf\xa3<Pg\x00;Pf\\;Pf\xaf;Pf\r;Pf\x00;Pfp;Pf\xb9;Pf\x0f;Pft;Pf\xdf;Pfi;PfK;Pf=>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<Qgj3EY\xa2+Mn\xf88p\xa6\xff<p\xa2\xff;j\x98\xff:d\x8e\xff<f\x90\xff@o\x9b\xffEw\xa7\xff9o\xa3\xff)Ea\xf07J^\x96;Pff;PfD;Pf$;Pf\x14:Oe\x08;Pf\x80;Pf\xd6;Pf.;Pf\x00;Pf\x00;Qf\x00;Of\x00=Uf\x00;Pfh;Pf\xe4;Pf\x97;Pf\x88;Pf\xac;Pf\xc6;Pf\xd78La\xea*B[\xfe:p\xa4\xffK\x82\xb7\xffP\x85\xb9\xffR\x87\xba\xffT\x88\xba\xffV\x89\xbb\xffP\x86\xb9\xff6h\x97\xff+?U\xfd;Od\xe6;Pf\xd5;Pf\xc3;Pf\xa8;Pf\x85;Pf\xa0;Pf\xe0;PfP;Pf\x00;Pe\x00:Pe\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x02;Pff;Pf\xc1;Pf\xbb;Pf\x9e;Pf~1CW\x8f(?V\xe9$@\\\xff0X\x80\xffK\x85\xbe\xff]\x92\xc6\xffb\x95\xc6\xffd\x96\xc7\xffa\x94\xc7\xffJ\x82\xb9\xff/Ru\xff)D_\xff.CY\xe04G[\x88;Pf\x81;Pf\xa3;Pf\xbd;Pf\xbd;PfU7K^\x00;Pe\x00;Pf\x00;Pf\x00;Pf\x0c:Of\x0f;Pf\x00;Pf\x00?Of\x00;Pf\t;Pf\x06\x1d,<\x00\x1e-=8#?[\xd7)V\x82\xff*\\\x8c\xff\'Jl\xff6b\x8e\xffP\x8a\xc4\xffa\x99\xd0\xffb\x99\xd0\xffQ\x89\xbf\xff8_\x86\xff0Tw\xff4d\x93\xff2\\\x84\xff%?Y\xca\x1c+:)\x01\r\x18\x00;Pf\x07;Pf\x08;Pe\x00;Pe\x00;Pf\x00;Pf\x0f;Pf\x07;Pf5;Pf\x88;Pf\x0b;Pf\x00:Pf\x00:Pe\x00*<O\x00\x1a\x1e%\x07#;S\xb0-\\\x8a\xff1f\x99\xff2f\x99\xff2d\x95\xff/Ty\xff5X|\xff=f\x8f\xff>f\x8e\xff8Z{\xff7]\x82\xff<m\x9d\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<f\x8f\xff>h\x91\xffBq\x9f\xffEw\xa8\xffFx\xa9\xffHy\xa9\xffFy\xa9\xff4h\x9a\xff%A]\xb8\x00\x00\x00\x03*<O\x00;Pf\x00;Pf\x00:Pf\x0b;Pf\x95;Pf\x81:Pg\x01;Pf\x00;Pf%;Pf\xc4;Pf\x83;Pf\x0b;Pf\x00Nh\x7f\x021BTN)Fd\xed8p\xa6\xffBy\xad\xffEz\xae\xffF{\xaf\xffH|\xaf\xffI~\xb0\xffJ\x7f\xb2\xffL\x80\xb2\xffM\x80\xb2\xffN\x81\xb2\xffP\x82\xb3\xffQ\x83\xb3\xffN\x81\xb2\xff8m\xa1\xff)C^\xd77I\\8Tq\x8c\x00;Pf\x00;Pf\x12;Pf\x98;Pf\xb8;Pf\x17;Pf\x00<Tg\x00;Pf\x00;Pf<;Pf\xd3;Pf\xa8;PfK;Pf\x9a:Nc\xe6+D^\xf29p\xa6\xffI\x81\xb7\xffN\x84\xb8\xffO\x85\xb9\xffQ\x86\xb9\xffR\x87\xba\xffS\x88\xba\xffU\x89\xbb\xffV\x8a\xbb\xffW\x8a\xbc\xffY\x8b\xbc\xff[\x8c\xbd\xffO\x85\xb9\xff7k\x9d\xff,BY\xf1;Oe\xe2;Pf\x8b;PfL;Pf\xb8;Pf\xc2;Pf\';Pf\x00;Pf\x00:Of\x00:Pe\x00;Of\x00;Pf1;Pf\xb8;Pf\xec;Pf\xc7<QgZ$6Is3`\x8b\xfdG\x84\xbe\xffV\x8d\xc2\xffY\x8e\xc3\xffZ\x8f\xc3\xff[\x90\xc3\xff\\\x91\xc4\xff]\x91\xc4\xff_\x92\xc5\xff`\x93\xc5\xffb\x95\xc6\xff_\x93\xc5\xffG\x83\xbc\xff0X\x80\xf6%6H`<Qgg;Pf\xd0;Pf\xeb;Pf\xaa;Pf";Pf\x00<Qh\x00;Of\x00\x00\x00\x00\x00;Pe\x00:Rd\x00;Pf\x00;Pf\x11;Pf;;Pf\x143G[\x00\x1a$/\x11\'A[\xb6<q\xa4\xffP\x8d\xc8\xff_\x96\xcc\xffc\x98\xcd\xffd\x99\xcd\xffe\x9a\xce\xffg\x9b\xce\xffh\x9b\xce\xffi\x9c\xcf\xfff\x9a\xce\xffQ\x8d\xc8\xff9k\x9c\xff%<T\x9d\x13\x18\x1f\x075I_\x00;Pf\x1a;Pf:;Pf\x0b;Pf\x00;Qg\x00:Od\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;Qe\x00;Pf\x00;Pf\x00;Pf\x00;Pf\x00%6H\x00 /@\x00\x1e*9$(C^\xbb;m\x9e\xffO\x8c\xc9\xff_\x9a\xd4\xffh\x9f\xd6\xffk\xa1\xd6\xffl\xa2\xd7\xffj\xa1\xd7\xffa\x9b\xd4\xffN\x89\xc5\xff8f\x94\xfd\'?X\xa7\x1d(5\x19\x1f.>\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<l\x9c\xfaF~\xb5\xffM\x88\xc1\xffM\x87\xc0\xffE{\xb1\xff:h\x96\xf8-No\xd1"5Io\x1a#.\x0e\x1f.>\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%<T\x96(B\\\xb2(B\\\xaf$:Q\x91 0@\\\x1a#.\x1d+Lj\x00\x1f.>\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_())

来源:https://blog.csdn.net/firseve/article/details/122500716

标签:python3,QT5,端口
0
投稿

猜你喜欢

  • Python创建多线程的两种常用方法总结

    2023-11-16 16:41:09
  • python3.6 实现AES加密的示例(pyCryptodome)

    2022-07-05 08:17:08
  • python用列表生成式写嵌套循环的方法

    2022-02-14 05:45:03
  • Python实现简单的俄罗斯方块游戏

    2022-11-17 16:56:58
  • sql2005与sql200数据导入导出

    2009-03-13 13:16:00
  • python基础教程项目三之万能的XML

    2022-09-22 05:33:25
  • mysql 之通过配置文件链接数据库

    2024-01-17 13:32:28
  • 关于go-zero服务自动收集问题分析

    2024-04-26 17:29:51
  • 关于TypeScript开发的6六个实用小技巧分享

    2024-04-16 08:59:26
  • python和opencv实现抠图

    2023-12-13 20:43:33
  • 利用Python语言的grpc实现消息传送详解

    2023-09-12 14:00:07
  • 二级下拉菜单代码

    2008-11-01 18:18:00
  • SQL进行排序、分组、统计的10个新技巧

    2009-01-23 13:59:00
  • Discuz!NT 论坛整合ASP程序论坛

    2011-03-31 10:40:00
  • Yii2 assets清除缓存的方法

    2024-05-13 09:51:47
  • python实现列表的排序方法分享

    2022-10-06 07:56:01
  • *.HTC 文件的简单介绍

    2008-11-24 17:36:00
  • Django框架 querySet功能解析

    2021-02-15 16:32:14
  • Python常见MongoDB数据库操作实例总结

    2023-07-08 08:48:34
  • SQLServer 存储过程简介与使用方法

    2009-07-07 14:06:00
  • asp之家 网络编程 m.aspxhome.com