parent
cdddffe5c0
commit
eecdb586ea
@ -0,0 +1,309 @@
|
|||||||
|
import sys
|
||||||
|
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidgetItem, QFileDialog
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
|
from newfile import Ui_MainWindow # 导入生成的UI类
|
||||||
|
from tcp_client import TCPClient
|
||||||
|
from tcp_server import TCPServer
|
||||||
|
from isIP import isIP,isPORT
|
||||||
|
from AES import *
|
||||||
|
from RSA_Module import *
|
||||||
|
from Zip_Module import *
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setupUi(self) # 设置UI
|
||||||
|
#初始化TCP服务器
|
||||||
|
self.client_conn = None
|
||||||
|
self.running = True
|
||||||
|
self.run_client = True
|
||||||
|
self.server =TCPServer()
|
||||||
|
self.conn =None
|
||||||
|
self.client = TCPClient()
|
||||||
|
self.client_conn = None
|
||||||
|
#client文件信号
|
||||||
|
# self.client_recv = TCPClient_recv()
|
||||||
|
self.client.receive_status.connect(self.add_list)
|
||||||
|
self.client.list_received.connect(self.add_list)
|
||||||
|
self.client.receive_progress.connect(self.update_receive_bar)
|
||||||
|
|
||||||
|
#连接按钮点击事件自动跳转到自定义槽函数
|
||||||
|
self.send_file.clicked.connect(self.show_send_page)
|
||||||
|
self.receive_file.clicked.connect(self.show_receive_page)
|
||||||
|
self.add_file.clicked.connect(self.read_file)
|
||||||
|
self.handler.clicked.connect(self.toggle_server)
|
||||||
|
self.receive.clicked.connect(self.toggle_client)
|
||||||
|
self.send.clicked.connect(self.send_files)
|
||||||
|
self.delete_file.clicked.connect(self.delete_filex)
|
||||||
|
self.empty_file.clicked.connect(self.delete_all_filex)
|
||||||
|
self.server.progress_updated.connect(self.update_current_bar)
|
||||||
|
|
||||||
|
|
||||||
|
def mk_temp_files(self):
|
||||||
|
"""创建临时文件夹"""
|
||||||
|
temp_dir = './.tempfile'
|
||||||
|
if not os.path.exists(temp_dir):
|
||||||
|
os.makedirs(temp_dir)
|
||||||
|
|
||||||
|
def del_temp_files(self):
|
||||||
|
"""删除临时文件夹及其内容"""
|
||||||
|
temp_dir = './.tempfile'
|
||||||
|
if os.path.exists(temp_dir):
|
||||||
|
try:
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
print(f"Temporary directory deleted: {temp_dir}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to delete temporary directory: {e}")
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""重写 closeEvent 方法,在窗口关闭时删除临时目录"""
|
||||||
|
self.del_temp_files()
|
||||||
|
# 调用父类的 closeEvent 方法,确保窗口正常关闭
|
||||||
|
super().closeEvent(event)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------------------------
|
||||||
|
#左上角三个按钮
|
||||||
|
#读文件
|
||||||
|
def read_file(self):
|
||||||
|
filename, _ =QFileDialog.getOpenFileName(self, "选取文件", "C:/", "All Files(*)")
|
||||||
|
if not filename:
|
||||||
|
return #如果用户取消选择=文件,直接返回
|
||||||
|
# 获取文件的字节大小
|
||||||
|
file_size_bytes = os.path.getsize(filename)
|
||||||
|
file_size_str = f"{file_size_bytes}字节"
|
||||||
|
# 找到当前表格的最后一行(非空行)
|
||||||
|
row_count = self.tableWidget.rowCount()
|
||||||
|
for row in range(row_count):
|
||||||
|
item = self.tableWidget.item(row, 0)
|
||||||
|
if not item or item.text().strip() == "": # 检查第一列是否为空或仅包含空白字符
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# 如果所有行都已填满,增加新行
|
||||||
|
self.tableWidget.insertRow(row_count)
|
||||||
|
row = row_count
|
||||||
|
self.tableWidget.setItem(row, 0, QTableWidgetItem(filename))
|
||||||
|
self.tableWidget.setItem(row, 1, QTableWidgetItem(file_size_str))
|
||||||
|
#删除文件
|
||||||
|
def delete_filex(self):
|
||||||
|
row_count = self.tableWidget.rowCount()
|
||||||
|
if row_count > 0:
|
||||||
|
for row in range(row_count):
|
||||||
|
item = self.tableWidget.item(row, 0)
|
||||||
|
if not item or item.text().strip() == "": # 检查第一列是否为空或仅包含空白字符
|
||||||
|
break
|
||||||
|
self.tableWidget.setItem(row-1, 0, QTableWidgetItem(""))
|
||||||
|
self.tableWidget.setItem(row-1, 1, QTableWidgetItem(""))
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
#删除全部文件
|
||||||
|
def delete_all_filex(self):
|
||||||
|
self.tableWidget.clearContents()
|
||||||
|
|
||||||
|
def read_table(self):
|
||||||
|
row_count = self.tableWidget.rowCount()
|
||||||
|
filenames = []
|
||||||
|
filesizes = []
|
||||||
|
newfilenames = []
|
||||||
|
newfilesizes = []
|
||||||
|
exts = []
|
||||||
|
for row in range(row_count):
|
||||||
|
filename_item = self.tableWidget.item(row, 0)
|
||||||
|
filetype_item = self.tableWidget.item(row, 1)
|
||||||
|
|
||||||
|
if filename_item is not None:
|
||||||
|
filenames.append(filename_item.text())
|
||||||
|
|
||||||
|
if filetype_item is not None:
|
||||||
|
filesizex = int(filetype_item.text().strip('字节'))
|
||||||
|
filesizes.append(filesizex)
|
||||||
|
for i in range(len(filenames)):
|
||||||
|
basename, ext = os.path.splitext(os.path.basename(filenames[i])) #不带扩展名的文件
|
||||||
|
aeskey = create_key(basename) #生成对称密钥
|
||||||
|
sign_message(filenames[i], './.tempfile/serverpri.pem', f'./.tempfile/{basename}_sig') #计算摘要加签名
|
||||||
|
|
||||||
|
with open(filenames[i],'rb') as f: #使用对称密钥对文件进行加密
|
||||||
|
data = f.read()
|
||||||
|
with open(f'./.tempfile/{basename}{ext}', 'wb') as s:
|
||||||
|
endata = AESencrypt(data, aeskey)
|
||||||
|
s.write(endata)
|
||||||
|
RSAencrypt('./.tempfile/new_clientpub.pem', aeskey, f'./.tempfile/{basename}_key')#对对称密钥进行加密
|
||||||
|
files_to_zip = [
|
||||||
|
f'./.tempfile/{basename}_sig',
|
||||||
|
f'./.tempfile/{basename}{ext}',
|
||||||
|
f'./.tempfile/{basename}_key'
|
||||||
|
]
|
||||||
|
zip_filename = f'./.tempfile/{basename}'
|
||||||
|
zip_files(zip_filename, files_to_zip)
|
||||||
|
newfilenames.append(zip_filename)
|
||||||
|
#获取文件大小
|
||||||
|
file_size_bytes = os.path.getsize(zip_filename)
|
||||||
|
newfilesizes.append(file_size_bytes)
|
||||||
|
#文件后缀
|
||||||
|
exts.append(ext)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return newfilenames,newfilesizes,exts
|
||||||
|
#----------------------------------------------------------------------------------
|
||||||
|
#服务端
|
||||||
|
def send_files(self):
|
||||||
|
filenames, filesizes, exts = self.read_table()
|
||||||
|
self.send_fileth(filenames, filesizes, exts)
|
||||||
|
def send_fileth(self, filenames, filesizes, exts):
|
||||||
|
if not self.conn:
|
||||||
|
self.update_status(f'服务器未连接')
|
||||||
|
return
|
||||||
|
self.thread_send = threading.Thread(target=self.send_file_all, kwargs={'filenames': filenames, 'filesizes': filesizes, 'exts': exts})
|
||||||
|
self.thread_send.start()
|
||||||
|
|
||||||
|
def send_file_all(self, filenames, filesizes, exts):
|
||||||
|
send_file = 0
|
||||||
|
i = 0
|
||||||
|
while i < len(filenames):
|
||||||
|
self.update_status(f"{filenames[i]}文件发送中")
|
||||||
|
if i + 1 == len(filenames):
|
||||||
|
index = -1
|
||||||
|
else:
|
||||||
|
index = i + 1
|
||||||
|
self.server.send_file(self.conn, filenames[i], filesizes[i], index, exts[i])
|
||||||
|
send_file += 1
|
||||||
|
state, fileindex = self.server.judge_send_status(self.conn)
|
||||||
|
i = i + 1
|
||||||
|
progress = int((send_file / len(filenames)) * 100)
|
||||||
|
self.update_total_bar(progress)
|
||||||
|
if not state:
|
||||||
|
i = fileindex - 1
|
||||||
|
self.update_status(f'{filenames[fileindex]}传输错误,重传中...')
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
self.update_status(f"文件全部发送完成")
|
||||||
|
self.server.wait_for_send = False
|
||||||
|
|
||||||
|
|
||||||
|
def toggle_server(self):
|
||||||
|
if self.running:
|
||||||
|
self.thread = threading.Thread(target=self.start_server)
|
||||||
|
self.thread.start()
|
||||||
|
else:
|
||||||
|
self.running = True
|
||||||
|
if self.thread and self.thread.is_alive():
|
||||||
|
self.thread.join()
|
||||||
|
self.handler.setText('启动服务器')
|
||||||
|
|
||||||
|
def start_server(self):
|
||||||
|
ip_address = self.IP_text.text().strip() # 读取并去除可能存在的空白字符
|
||||||
|
port = self.PORT_text.text().strip()
|
||||||
|
if not (isIP(ip_address) and isPORT(port)):
|
||||||
|
# 如果不是有效的 IP 地址
|
||||||
|
self.update_status('ip is error.')
|
||||||
|
return
|
||||||
|
self.handler.setText('停止服务器')
|
||||||
|
self.running = False
|
||||||
|
self.update_status(f'等待客户端连接...')
|
||||||
|
self.server.ip = ip_address
|
||||||
|
self.server.port = int(port)
|
||||||
|
|
||||||
|
self.server.run_server()
|
||||||
|
conn, addr = self.server.tcp_server.accept()
|
||||||
|
self.conn = conn # 保存客户端连接
|
||||||
|
if conn:
|
||||||
|
# self.server.client_conn = True
|
||||||
|
self.update_status(f'客户端连接成功')
|
||||||
|
else:
|
||||||
|
self.update_status(f'客户端连接失败')
|
||||||
|
state, pubname = self.server.recv_clientpub(self.conn)
|
||||||
|
if state:
|
||||||
|
self.update_status(f'{pubname}接收成功')
|
||||||
|
else:
|
||||||
|
self.update_status(f'{pubname}接收失败')
|
||||||
|
self.server.send_serverpub(self.conn)
|
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------------
|
||||||
|
#客户端
|
||||||
|
|
||||||
|
def toggle_client(self):
|
||||||
|
if self.run_client:
|
||||||
|
self.thread_client = threading.Thread(target=self.start_client)
|
||||||
|
self.thread_client.start()
|
||||||
|
else:
|
||||||
|
self.run_client = True
|
||||||
|
if self.thread_client and self.thread_client.is_alive():
|
||||||
|
self.thread_client.join()
|
||||||
|
self.receive.setText('接收')
|
||||||
|
def start_client(self):
|
||||||
|
ip = self.IP_receive_text.text().strip() # 读取并去除可能存在的空白字符
|
||||||
|
port = self.PORT_receive_text.text().strip()
|
||||||
|
|
||||||
|
if not (isIP(ip) and isPORT(port)):
|
||||||
|
# 如果不是有效的 IP 地址
|
||||||
|
self.update_receive_play('ip or port is error.')
|
||||||
|
return
|
||||||
|
port = int(port)
|
||||||
|
self.receive.setText('接收中')
|
||||||
|
self.run_client = False
|
||||||
|
self.update_receive_play(f'服务端连接中')
|
||||||
|
time.sleep(2)
|
||||||
|
self.client_conn = self.client.connect(ip, port)
|
||||||
|
if self.client_conn:
|
||||||
|
self.receive.setEnabled(False)
|
||||||
|
self.update_receive_play(f'连接服务端成功')
|
||||||
|
else:
|
||||||
|
self.update_receive_play(f'连接服务端失败')
|
||||||
|
return
|
||||||
|
self.client.send_clientpub(self.client_conn)
|
||||||
|
state, pubname = self.client.recv_serverpub(self.client_conn)
|
||||||
|
if state:
|
||||||
|
self.update_receive_play(f'{pubname}接收成功')
|
||||||
|
else:
|
||||||
|
self.update_receive_play(f'{pubname}接收失败')
|
||||||
|
self.client.receive(self.client_conn)
|
||||||
|
self.receive.setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------------
|
||||||
|
#更新显示常用函数。
|
||||||
|
def update_current_bar(self, value):
|
||||||
|
self.current_status_bar.setValue(value)
|
||||||
|
|
||||||
|
def update_total_bar(self, value):
|
||||||
|
self.total_status_bar.setValue(value)
|
||||||
|
|
||||||
|
def update_receive_bar(self, value):
|
||||||
|
self.receive_bar.setValue(value)
|
||||||
|
|
||||||
|
def add_list(self, text):
|
||||||
|
if text:
|
||||||
|
item = QtWidgets.QListWidgetItem(text) # 创建一个新的 QListWidgetItem
|
||||||
|
self.receive_widget.addItem(item) # 将新项目添加到 QListWidget
|
||||||
|
self.receive_widget.scrollToItem(item) # 滚动到最新添加的项目
|
||||||
|
|
||||||
|
def update_status(self, message):
|
||||||
|
self.status_show.setText(message)
|
||||||
|
def update_receive_play(self, message):
|
||||||
|
self.receive_play.setText(message)
|
||||||
|
def show_send_page(self):
|
||||||
|
"""切换到发送文件页面"""
|
||||||
|
self.stackedWidget.setCurrentIndex(0)
|
||||||
|
|
||||||
|
def show_receive_page(self):
|
||||||
|
"""切换到接收文件页面"""
|
||||||
|
self.stackedWidget.setCurrentIndex(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = MainWindow()
|
||||||
|
window.show() # 显示窗口
|
||||||
|
window.mk_temp_files()
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
|
Loading…
Reference in new issue