原版 python3 QT5 端口转发工具_firseve的专栏-CSDN博客
# -*- coding: utf-8 -*-
# 制作本地可执行文件
# pyinstaller -F -i ico.ico -w port.py
import datetime
import sys
import json
import socket,threading
import os
import re
import traceback
from PyQt5 import QtWidgets,QtCore
from PyQt5.QtCore import QCoreApplication, QEvent
from PyQt5.QtWidgets import QApplication, QWidget, QTextBrowser, QMessageBox, QStatusBar, QSystemTrayIcon, QAction, \
QMenu
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)
if os.path.exists('ico.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, 180))
# 状态栏
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
# 渲染UI
self.retranslateUi(MQt)
# 绑定槽函数
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("MainWindow", "ports"))
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,pushButton,stopButton):
threading.Thread.__init__(self,daemon=True)
self.targethost = targethost
self.targetport = targetport
self.targetTxt = targetTxt
self.pushButton = pushButton
self.stopButton = stopButton
try:
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)
except Exception as e:
print("启动失败")
self.targetTxt.append("启动本地监听端口失败")
self.pushButton.setEnabled(True)
self.stopButton.setEnabled(False)
tp.showMessage('启动失败', '端口占用无法启动', icon=3)
def run(self):
while True:
try:
client_fd, addr = self.sock.accept()
except :
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)
nowDateTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
self.targetTxt.append('{} - new connect'.format(nowDateTime))
# 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.statusBar.showMessage("使用 Python QT5 开发")
# 加载配置
self.load()
# 事件绑定
def changeEvent(self, event):
if event.type() == QEvent.WindowStateChange:
if self.isMinimized():
print('最小化窗口')
self.hide()
QWidget.changeEvent(self, event)
elif self.isMaximized():
self.sBar.showMessage('最大化窗口', 1000)
print('最大化窗口')
elif self.isFullScreen():
self.sBar.showMessage('全屏显示', 1000)
print('全屏显示')
elif self.isActiveWindow():
# 恢复显示
print('活动窗口')
QWidget.changeEvent(self, event)
else:
print(event)
def mousePressEvent(self,event):
print("mousePressEvent:{}".format(event))
def stop(self):
print("stop")
global isRunning
isRunning = False
global thread0
thread0.stop()
# self.thread0.setDaemon(False)#关了就全退出了
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,self.pushButton,self.stopButton)
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()
# 关闭所有窗口,也不关闭应用程序
# QApplication.setQuitOnLastWindowClosed(False)
# 在系统托盘处显示图标
tp = QSystemTrayIcon(win)
if os.path.exists('ico.ico'):
tp.setIcon(QIcon('ico.ico'))
else:
icon = QPixmap()
icon.loadFromData(iconB)
tp.setIcon(QIcon(icon))
# 显示窗口,先置顶显示,再改为普通显示
def showWin():
# win.setWindowState(QtCore.Qt.WindowNoState)
win.hide()
win.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
win.setWindowState(QtCore.Qt.WindowActive)
win.show()
win.setWindowFlags(QtCore.Qt.Widget)
win.show()
# 退出程序
def quitApp():
QCoreApplication.instance().quit()
def showInfo():
QMessageBox.information(None, "关于", "联系地址\nhttps://blog.csdn.net/firseve/\n", QMessageBox.Yes)
# 设置系统托盘图标的菜单
a1 = QAction('&显示(Show)', triggered=showWin)
a2 = QAction('&退出(Exit)',triggered=quitApp) # 直接退出可以用qApp.quit
a3 = QAction('&关于(Info)', triggered=showInfo)
tpMenu = QMenu()
tpMenu.addAction(a1)
tpMenu.addAction(a3)
tpMenu.addAction(a2)
tp.setContextMenu(tpMenu)
# 信息提示
# 参数1:标题
# 参数2:内容
# 参数3:图标(0没有图标 1信息图标 2警告图标 3错误图标),0还是有一个小图标
def message():
# tp.showMessage('tp', 'tpContent', icon=1)
# print("弹出的信息被点击了")
pass
tp.messageClicked.connect(message)
def act(reason):
# 鼠标点击icon传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键,4是用鼠标中键点击
if reason == 2 or reason == 3 or reason == 4:
showWin()
# tp.showMessage('ports', 'tpContent', icon=0)
# print("系统托盘的图标被点击了")
tp.activated.connect(act)
# 不调用show不会显示系统托盘
tp.show()
sys.exit(app.exec_())