You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 lines
6.0 KiB

from socket import *
import struct
import json
from RSA_Module import *
from Zip_Module import *
from AES import AESdecrypt
from PyQt5.QtCore import pyqtSignal, QObject
class TCPClient(QObject):
# 定义自定义信号
list_received = pyqtSignal(str)
receive_status = pyqtSignal(str) # 当发生错误时发出或者一些状态文件
receive_progress = pyqtSignal(int)
def __init__(self, buffsize=1024):
super().__init__()
self.buffsize = buffsize
self.tcp_client = socket(AF_INET, SOCK_STREAM)
self.connected = False
def connect(self, ip, port):
self.tcp_client.connect_ex((ip, port))
self.connected = True
generate_rsakey('clientpub.pem', 'clientpri.pem')
return self.tcp_client
def send_clientpub(self, client_conn):
filesize = os.path.getsize('./.tempfile/clientpub.pem')
newfilename = 'new_' + os.path.basename('./.tempfile/clientpub.pem')
dirc = {
'filename': newfilename,
'filesize': filesize,
}
head_info = json.dumps(dirc)
head_info_len = struct.pack('i', len(head_info))
client_conn.send(head_info_len)#发送head_info的长度
client_conn.send(head_info.encode('utf-8'))
#发送文件数据
with open('./.tempfile/clientpub.pem', 'rb') as f:
data = f.read()
client_conn.sendall(data)
def recv_serverpub(self, client_conn):
head_info_len = client_conn.recv(4)
head_info_len = struct.unpack('i',head_info_len)[0]
#接收并解析报头内容
head_info = client_conn.recv(head_info_len)
dirc = json.loads(head_info.decode('utf-8'))
filename = dirc['filename']
filesize = dirc['filesize']
received_size = 0
with open(f'./.tempfile/{filename}', 'wb') as f:
while received_size < filesize:
if filesize - received_size > self.buffsize:
data = client_conn.recv(self.buffsize)
f.write(data)
received_size += len(data)
else:
data = client_conn.recv(filesize - received_size)
f.write(data)
received_size += len(data)
if received_size == filesize:
return True, filename
else:
return False, filename
def receive(self, client_conn):
if not client_conn:
self.receive_status.emit("未连接到服务端")
return
try:
i = 1
while True:
head_info_len = client_conn.recv(4)
if head_info_len == 4:
self.receive_status.emit('正在接收文件中...')
head_info_len = struct.unpack('i', head_info_len)[0]
# 接收并解析报头内容
head_info = client_conn.recv(head_info_len)
dirc = json.loads(head_info.decode('utf-8'))
filename = dirc['filename']
filesize_bytes = dirc['filesize_bytes']
fileindex = dirc['fileindex']
ext = dirc['fileext']
lineEdit1 = '正在接收第' + str(i) + \
'号文件【' + filename + '】......'
self.list_received.emit(lineEdit1)
received_size = 0
with open(f'./.tempfile/{filename}', 'wb') as f:
while received_size < filesize_bytes:
if filesize_bytes - received_size > self.buffsize:
data = client_conn.recv(self.buffsize)
f.write(data)
received_size += len(data)
else:
data = client_conn.recv(filesize_bytes - received_size)
f.write(data)
received_size += len(data)
self.receive_progress.emit(int((received_size / filesize_bytes) * 100))
lineEdit2 = '成功接收第' + str(i) + \
'号文件【' + filename + '】 --> ' + \
os.getcwd() + '\\.tempfile\\' + filename
self.list_received.emit(lineEdit2)
if not self.sign_file(filename, ext): #发送签名状态
self.send_state(client_conn, i, False)
self.list_received.emit(f'{i}号文件签名错误,重新接收...')
else:
self.send_state(client_conn, i, True)
self.list_received.emit(f'{i}号文件签名验证成功')
i = i + 1
if fileindex == -1:
self.receive_status.emit('文件全部安全接收完成')
break
except Exception as e:
print(f'接收文件失败: {e}')
return
def sign_file(self, filename, ext):
unzip_file(f'./.tempfile/{filename}', './.tempfile')
aeskey = RSAdecrypt('./.tempfile/clientpri.pem', f'./.tempfile/{filename}_key')
decrypted_message = AESdecrypt(f'./.tempfile/{filename}{ext}', aeskey)
state = verify_signature(decrypted_message,'./.tempfile/new_serverpub.pem',f'./.tempfile/{filename}_sig')
if state:
with open(f'./.tempfile/{filename}{ext}', 'rb') as f :
data = f.read()
with open(f'./{filename}{ext}', 'wb') as s:
s.write(data)
return state
def send_state(self,client_conn, fileindex, state):
dirc = {
'fileindex': fileindex,
'state': state,
}
head_info = json.dumps(dirc)
head_info_len = struct.pack('i', len(head_info))
client_conn.send(head_info_len) # 发送head_info的长度
client_conn.send(head_info.encode('utf-8'))