当前位置: 首页 > news >正文

实验四 增强型可靠文件传输系统

一、实验目的和任务

  1. 掌握基于队列的多文件传输机制
  2. 理解断点续传的实现原理
  3. 学习文件传输完整性保障方法

二、实验内容

基础功能验证

  1. 单文件传输功能测试
  2. 服务器状态监控测试
  3. 传输日志记录验证

新增功能实现

  1. 多文件队列传输功能
  2. 断点续传支持

三、实验步骤

4.1 客户端功能扩展

参考代码:

关键代码修改点:

文件队列管理:
# 新增队列和状态变量
self.file_queue = queue.Queue()
self.is_transferring = False
# 修改后的文件选择方法
def select_file(self):filepaths = filedialog.askopenfilenames()if filepaths:for filepath in filepaths:self.file_queue.put(filepath)self.log.insert(END, f"已添加: {os.path.basename(filepath)}\n")if not self.is_transferring:threading.Thread(target=self.process_queue).start()
新增队列处理线程:
def process_queue(self):self.is_transferring = Truewhile not self.file_queue.empty():filepath = self.file_queue.get()self.upload_file(filepath)
self.is_transferring = False
断点续传功能:
上传文件方法修改def upload_file(self, filepath):try:client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client.connect(('localhost', 12345))# 发送文件元数据filename = os.path.basename(filepath)filesize = os.path.getsize(filepath)client.send(f"{filename} |{filesize}".encode())# 等待服务器确认ack = client.recv(1024).decode()if ack.startswith('RESUME'):recieved = int(ack.split('|')[1])mode = 'rb+'  #从断点处继续读else:recieved = 0mode = 'rb'# 分块传输文件with open(filepath, mode) as f:f.seek(recieved)while recieved <filesize:chunk = f.read(1024)if chunk:client.send(chunk)recieved += len(chunk)self.log.insert(END, f"{filename} 传输成功\n")except Exception as e:self.log.insert(END, f"错误: {e}\n")finally:client.close()

完整python脚本如下:

import socket
import os
import threading
import queue
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
class FileTransferClient:def __init__(self, root):self.root = rootself.root.title("文件传输客户端")# 文件队列和状态self.file_queue = queue.Queue()self.is_transferring = False# 创建界面组件self.create_widgets()def create_widgets(self):# 文件选择按钮self.select_btn = Button(self.root, text="选择文件", command=self.select_file)self.select_btn.pack(pady=10)# 传输日志self.log = Text(self.root, height=15, width=60)self.log.pack(pady=10)def select_file(self):filepaths = filedialog.askopenfilenames()if filepaths:for filepath in filepaths:self.file_queue.put(filepath)self.log.insert(END, f"已添加: {os.path.basename(filepath)}\n")if not self.is_transferring:threading.Thread(target=self.process_queue).start()def process_queue(self):self.is_transferring = Truewhile not self.file_queue.empty():filepath = self.file_queue.get()self.upload_file(filepath)self.is_transferring = Falsedef upload_file(self, filepath):try:client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client.connect(('localhost', 12345))# 发送文件元数据filename = os.path.basename(filepath)filesize = os.path.getsize(filepath)client.send(f"{filename}|{filesize}".encode())# 等待服务器确认ack = client.recv(1024).decode()if ack.startswith('RESUME'):received = int(ack.split('|')[1])mode = 'rb+'else:received = 0mode = 'rb'# 分块传输文件with open(filepath, mode) as f:f.seek(received)while received < filesize:data = f.read(1024)if not data:breakclient.send(data)received += len(data)self.log.insert(END, f"{filename} 传输成功\n")except Exception as e:self.log.insert(END, f"错误: {e}\n")finally:client.close()
if __name__ == "__main__":root = Tk()app = FileTransferClient(root)root.mainloop()

4.2 服务器功能扩展

参考代码:

关键代码修改点:

断点续传支持:
def handle_client(self, client_socket):# 检查文件是否存在if os.path.exists(filename):received = os.path.getsize(filename)client_socket.send(f"RESUME|{received}".encode())mode = 'ab'  # 追加模式else:client_socket.send(b"ACK")mode = 'wb'received = 0

完整python脚本如下:  


import socket
import os
import threading
from datetime import datetime
class FileTransferServer:def __init__(self, host='localhost', port=12345):self.host = hostself.port = portself.server_socket = Noneself.running = Falsedef start(self):self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.server_socket.bind((self.host, self.port))self.server_socket.listen(5)self.running = Trueprint(f"服务器启动,监听 {self.host}:{self.port}")while self.running:try:client_socket, addr = self.server_socket.accept()print(f"新连接来自: {addr}")# 为每个客户端创建新线程client_thread = threading.Thread(target=self.handle_client,args=(client_socket,))client_thread.start()except Exception as e:print(f"服务器错误: {e}")breakdef stop(self):self.running = Falseif self.server_socket:self.server_socket.close()print("服务器已停止")def handle_client(self, client_socket):try:# 接收文件元数据metadata = client_socket.recv(1024).decode()filename, filesize = metadata.split('|')filesize = int(filesize)# 检查文件是否存在if os.path.exists(filename):received = os.path.getsize(filename)client_socket.send(f"RESUME|{received}".encode())mode = 'ab'  # 追加模式else:client_socket.send(b"ACK")mode = 'wb'received = 0# 接收文件数据with open(filename, mode) as f:while received < filesize:data = client_socket.recv(1024)if not data:breakf.write(data)received += len(data)print(f"文件 {filename} 接收完成 ({received}/{filesize} bytes)")except Exception as e:print(f"处理客户端时出错: {e}")finally:client_socket.close()
if __name__ == "__main__":server = FileTransferServer()try:server.start()except KeyboardInterrupt:server.stop()

4.3 实验验证步骤

  1. 基础传输测试:
  1. 启动Server.py
  2. 运行Client.py
  3. 选择单个文件传输
  4. 观察服务器接收情况
  1. 多文件队列测试:
  1. 启动Server2.py
  2. 运行Client2.py
  3. 同时选择多个文件(建议3-5个)
  4. 观察队列传输顺序和日志记录
  1. 断点续传测试:
  1. 传输大文件(>50MB)
  2. 在传输过程中强制关闭客户端
  3. 重新启动传输同一文件
  4. 验证文件完整性(通过文件大小比对)

四、测试结果

五、思考题

1.MD5校验是否能完全保证文件正确性?为什么?

        MD5校验不能完全保证文件的正确性。虽然MD5可以用来检测文件完整性,因为它通过生成一个固定长度的哈希值来唯一标识文件内容,但如果两个不同的文件生成了相同的MD5哈希值(这种情况称为哈希碰撞),那么MD5校验就无法区分这两个文件了。此外,MD5已经被证明不够安全,存在被恶意攻击者故意构造碰撞的情况。因此,对于需要更高安全性的场景,通常推荐使用更安全的哈希算法,如SHA-256。

2.进度条更新为什么要用after()方法?

        在GUI编程中,after()方法常用于非阻塞地执行某些任务,比如定时更新进度条。这是因为after()方法可以在指定的时间间隔后执行一个函数或方法调用,而不需要阻塞主线程。这样可以保持用户界面的响应性,防止因为长时间的计算或网络操作导致界面卡顿。

3.如何实现服务端的多客户端并发处理?

        实现服务端的多客户端并发处理通常可以采用多线程或多进程的方式。例如,在Python中可以使用socket库结合threadingmultiprocessing库来为每个客户端创建一个独立的线程或进程,从而实现并发。另一种方法是使用异步编程,如asyncio库,通过事件循环管理多个客户端的请求,这种方式在处理大量并发连接时效率更高。

4.传输过程中突然关闭窗口会导致什么问题?如何解决?

        传输过程中突然关闭窗口可能会导致数据传输不完整,文件损坏,或者服务端和客户端之间的连接异常中断。为了解决这个问题,通常可以采用以下措施:

  • 实现数据包的确认机制,确保每个数据包都被正确接收。

  • 使用断点续传功能,使得在传输中断后可以从上次中断的位置继续传输。

  • 设计良好的错误处理机制,能够在检测到连接中断时尝试恢复连接或通知用户重新传输文件。

http://www.xdnf.cn/news/279343.html

相关文章:

  • 电容电阻作用
  • PostgreSQL 表的年龄(age)详解
  • 从 Java 开发到 AI 工程师:全面学习指南
  • C++多继承陷阱全解:虚析构函数与虚表布局的工程实践
  • 方案精读:业财融合转型路径和华为实践【附全文阅读】
  • 质检报告警示:亚马逊等平台3成节能插座不达标
  • [特殊字符]Spring Boot 后台使用 EasyExcel 实现数据报表导出(含模板、样式、美化)
  • 【iOS】 方法交换
  • Linux文件权限管理:chmod修改权限 与 chown修改所有者
  • Android第三次面试总结之网络篇补充
  • 力扣-链表-2 两数相加
  • 情绪ABC——AI与思维模型【93】
  • # 基于SIFT的图像相似性检测与拼接:Python实现与解析
  • 精品,CentOS7.9 Yum安装Nginx,并配置JSON日志格式
  • Matlab/Simulink - BLDC直流无刷电机仿真基础教程(七) - 波形解析专题P2
  • Java 中使用 Callable 创建线程的方法
  • FastApi快速实践
  • React class 的组件库与函数组件适配集成
  • C++函数总结
  • 【Java学习笔记】方法重载
  • 以太坊智能合约开发框架:Hardhat v2 核心功能从入门到基础教程
  • 深入浅出数据库管理系统
  • 工程师 - 汽车分类
  • 【AI面试准备】掌握常规的性能、自动化等测试技术,并在工作中熟练应用
  • Jenkis安装、配置及账号权限分配保姆级教程
  • 高性能 WEB 服务器 Nginx:多虚拟主机实现!
  • llfc项目TCP服务器笔记
  • Linux常用命令30——groupadd创建新的用户组
  • 状态值函数与状态-动作值函数
  • MVP架构梳理