【网络编程与 Socket】用 Python 写一个简易文件传输器
用 Python 写一个简易文件传输器(含多实例 + 项目实战 + 调试技巧)
一、基础准备:Socket 是怎么传文件的?
文件怎么传?思想只有一句话:
读取文件 → 发送字节流 → 对端接收 → 写入文件
换句话说,文件传输就是数据流的搬运。
1. 正面示例:最小可运行 socket 程序
服务器(server.py):
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("0.0.0.0", 9000))
server.listen(1)
print("等待客户端连接...")
conn, addr = server.accept()
print(f"客户端已连接:{addr}")
conn.send(b"Hello from server")
conn.close()
server.close()
客户端(client.py):
import socket
client = socket.socket()
client.connect(("127.0.0.1", 9000))
data = client.recv(1024)
print("收到:", data)
client.close()
这个版本能跑,但距离“文件传输器”还有若干星系的距离。
2. 错误示例:新手最常见的发送 bug
f = open("a.jpg", "rb")
data = f.read()
sock.send(data) # ❌ 看起来没问题,其实大问题!
原因:send() 不保证送完全部数据,需要循环发送:
sock.sendall(data)
或手动循环:
while True:
chunk = f.read(4096)
if not chunk:
break
sock.send(chunk)
调试技巧:使用 netstat 或 tcpdump 查看连接是否建立
Linux/macOS:
netstat -an | grep 9000
Windows Powershell:
netstat -ano | findstr 9000
看到 LISTENING 或 ESTABLISHED 才说明 socket 工作正常。
二、项目实战:构建可传任意文件的文件传输器
接下来我们写一个能完整运行、可传任意文件的“简易文件传输器”。
项目结构
file_transfer/
server.py
client.py
三、服务器端:支持多线程、多用户同时上传文件
关键技术点:
- 每来一个客户端连接,就开启一个线程处理它
- 先收文件大小,再收文件内容
- 循环接收,直到收满为止
server.py 完整示例
import socket
import threading
import os
def handle_client(conn, addr):
print(f"[+] 客户端连接:{addr}")
# 1. 接收文件名长度
filename_len = int(conn.recv(8).decode().strip())
filename = conn.recv(filename_len).decode()
# 2. 接收文件大小
filesize = int(conn.recv(16).decode().strip())
print(f"开始接收文件:{filename} 大小:{filesize} bytes")
# 3. 接收文件内容
received = 0
with open("recv_" + filename, "wb") as f:
while received < filesize:
data = conn.recv(4096)
if not data:
break
f.write(data)
received += len(data)
print(f"进度:{received}/{filesize}", end="\r")
print(f"\n文件接收完成:{filename}")
conn.close()
def main():
server = socket.socket()
server.bind(("0.0.0.0", 9000))
server.listen(5)
print("服务器已启动,等待客户端上传文件...")
while True:
conn, addr = server.accept()
t = threading.Thread(target=handle_client, args=(conn, addr))
t.start()
if __name__ == "__main__":
main()
四、客户端:上传文件到服务器
client.py 完整示例
import socket
import os
def send_file(path):
client = socket.socket()
client.connect(("127.0.0.1", 9000))
filename = os.path.basename(path)
filesize = os.path.getsize(path)
# 1. 发送文件名长度(8字节对齐)
client.send(f"{len(filename):<8}".encode())
client.send(filename.encode())
# 2. 发送文件大小(16字节对齐)
client.send(f"{filesize:<16}".encode())
# 3. 发送文件内容
with open(path, "rb") as f:
while True:
data = f.read(4096)
if not data:
break
client.sendall(data)
client.close()
print("文件发送完毕")
send_file("test.jpg") # 发送任意文件
五、错误示例:可能让文件损坏的坑
坑 1:用 recv(1024) 接收文件大小,结果被拆包
原因:TCP 是字节流协议,没有消息边界,所以:
recv(16)
可能一次收不到 16 字节。
解决方法:要自己写“固定长度报文”或“分段协议”。
坑 2:未 flush 缓冲区导致文件不完整
如果写:
f.write(data)
但未及时关闭文件,内容未写入磁盘。
解决:使用 with open(...) 自动 flush 与 close。
坑 3:客户端单线程会卡住 GUI 或其他逻辑
解决:客户端发送操作独立线程化。
六、调试技巧:文件收不到怎么办?
常见问题与排查方式:
- 是否端口被占用 → 用 netstat 查
- 是否传输过程中卡住 → 打印接收字节计数
- 文件大小不一致 → 可能粘包或 recv 裁剪
- 是否 firewall 阻塞 → 关闭系统防火墙测试
- recv 返回空字符串 → 对端断开连接
把这些排查写进调试日志,非常有用:
print(f"[DEBUG] recv len={len(data)}")
七、高级技巧:让你的传输器更专业
以下技巧非常适合课程设计、CSDN 进阶文章、真实项目。
1. 进度条显示
可以用 tqdm:
from tqdm import tqdm
2. 断点续传 (resume upload)
实现思路:
- 服务器检查
recv_xxx.file是否存在 - 如果文件已经有部分长度,告知客户端 resume_offset
- 客户端从 offset 开始读取并传输
这是简易 FTP 的核心。
3. 传输校验(MD5)
防止传输损坏:
import hashlib
md5 = hashlib.md5(open("file").read()).hexdigest()
客户端和服务器都计算 md5,对比即可。
4. 大文件分块传输
对于几GB的大文件,不能一次性读取,用 chunk 处理更稳。
八、工作中的实际应用
这个项目虽然简易,但非常接近实际企业生产环境中的:
- 云服务之间的文件同步
- 日志系统把文件 push 到 Log Server
- 大模型训练时传数据集
- IoT 设备上传数据文件
- DevOps 工具中收集机器快照
若你未来从事 AIOps 或云计算方向,文件传输、流控、可靠传输机制都会非常重要。
九、拓展:背后的网络原理
学习 socket 传文件时,建议顺带理解一些核心概念:
1. TCP 粘包 / 拆包
原因:TCP 不保证一发一收,需要自定义协议。
2. 三次握手 / 四次挥手
连接建立与断开的基本过程。
3. 滑动窗口
TCP 提升性能的关键。
4. 流控与拥塞控制
保障网络不会被拖垮。
这些原理并不是必须掌握,但会让你写出的文件传输器更稳、更快、更专业。
AI 创作声明:本文部分内容由 AI 辅助生成,并经人工整理与验证,仅供参考学习,欢迎指出错误与不足之处。
更多推荐



所有评论(0)