1. 基于TCP协议的文件上传和下载
通过输入get/put file_path来实现对于文件的上传到服务端和从服务端下载文件,也可以对传输的文件进行MD5 check.
但是缺点很多,输入指令麻烦,只是在本地测试,只是单行,没有实现并发效果.现在这只是针对TCP粘包问题的小测试
# _*_ coding utf-8 _*_
# george
# time: 2024/1/30上午9:26
# name: cmd_file_server.py
# comment: 文件传输服务端
import socket
import json
import hashlib
from pathlib import Path
# 获取传递文件的md5值
def get_md5(cmd_path: str) -> str:
file_path = Path(cmd_path)
with open(file_path, "rb") as f:
m1 = hashlib.md5(f.read())
return m1.hexdigest()
# 传输文件给客户端:
def transfer_to_client(request_file, conn):
f = Path(request_file)
header = {
"file_name": f.name,
"file_size": f.stat().st_size,
"md5": get_md5(request_file)
}
header_json = json.dumps(header)
header_bytes = header_json.encode("utf-8")
header_h = bytes(str(len(header_bytes)), "utf-8").zfill(4)
conn.send(header_h)
conn.send(header_bytes)
with open(request_file, "rb") as f:
while True:
res = f.read(1024)
if not res:
break
conn.send(res)
print("文件传输完毕")
def receive_from_client(conn):
# 先拿头部长度
header_size = int(conn.recv(4).decode("utf-8"))
print("hear_size",header_size)
# 拿头部信息
header_json = conn.recv(header_size).decode("utf-8")
header = json.loads(header_json)
print(f"客户端传递文件的头部:{header}")
data_size = header["file_size"]
recv_size = 0
# data = b'' # 如果是大文件,就开一个文件,边收便往文件里面写
save_file_path = Path.home() / "Desktop" / "server" / header["file_name"]
# 文件接收
with open(save_file_path, "wb") as f:
while recv_size < data_size:
res = conn.recv(1024)
recv_size += len(res)
f.write(res)
print("数据接收成功")
# MD5 check
save_file_md5 = get_md5(save_file_path)
if save_file_md5 == header["md5"]:
print("MD5 check pass 数据完整性校验成功")
else:
print("MD5 check fail 数据完整性校验失败")
def main():
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.bind(("0.0.0.0", 5002))
sk.listen(5)
print("服务端启动成功,在5000端口等待连接")
while True: # 服务端 --> 连接循环
conn, addr = sk.accept() # windows客户端异常断开连接
print(f"连接对象是:{conn}")
print(f"ip和端口为:{addr}")
# 5. 数据传输
while True:
try:
cmd = conn.recv(1200)
except:
break
if not cmd: # mac客户端异常断开连接
break
data = cmd.decode("utf-8")
print(f"客户端发送过来的数据为:{data}")
if data == "q":
break
op, client_file_path = data.split()
if op == "get":
transfer_to_client(client_file_path, conn)
if op == "put":
receive_from_client(conn)
# 6. 结束服务
conn.close()
# 7. 关闭server(可选)
# sk.close()
if __name__ == "__main__":
main()
# _*_ coding utf-8 _*_
# george
# time: 2024/1/30上午9:26
# name: cmd_file_client.py
# comment: 文件传输客户端
import socket
import json
import hashlib
from pathlib import Path
# 获取传递文件的md5值
def get_md5(cmd_path: str) -> str:
file_path = Path(cmd_path)
with open(file_path, "rb") as f:
m1 = hashlib.md5(f.read())
return m1.hexdigest()
# 下载文件
def download_file(cmd):
while True:
if not cmd: # 避免发空问题
continue
if cmd == "q":
break
sk.send(cmd.encode("utf-8"))
# 先拿头部长度
header_size = int(sk.recv(4).decode("utf-8"))
# 拿头部信息
header_json = sk.recv(header_size).decode("utf-8")
header = json.loads(header_json)
print(header)
data_size = header["file_size"]
recv_size = 0
# data = b'' # 如果是大文件,就开一个文件,边收便往文件里面写
save_file_path = Path.home() / "Desktop" / "tt" / header["file_name"]
# 文件接收
with open(save_file_path, "wb") as f:
while recv_size < data_size:
res = sk.recv(1024)
recv_size += len(res)
f.write(res)
print("数据接收成功")
# MD5 check
save_file_md5 = get_md5(save_file_path)
if save_file_md5 == header["md5"]:
print("MD5 check pass 数据完整性校验成功")
break
else:
print("MD5 check fail 数据完整性校验失败")
break
# 4.关闭连接
sk.close()
# 上传文件
def upload_file(cmd):
while True:
if not cmd: # 避免发空问题
continue
if cmd == "q":
break
sk.send(cmd.encode("utf-8"))
op, request_file = cmd.split()
f = Path(request_file)
header = {
"file_name": f.name,
"file_size": f.stat().st_size,
"md5": get_md5(request_file)
}
header_json = json.dumps(header)
header_bytes = header_json.encode("utf-8")
header_h = bytes(str(len(header_bytes)), "utf-8").zfill(4)
sk.send(header_h)
sk.send(header_bytes)
with open(request_file, "rb") as f:
while True:
res = f.read(1024)
if not res:
break
sk.send(res)
print("文件传输完毕")
break
# 4.关闭连接
sk.close()
if __name__ == "__main__":
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.connect(("0.0.0.0", 5002))
cmd = input("请输入文件传入路径>>>").strip()
op = cmd.split()[0]
if op == "get":
download_file(cmd)
if op == "put":
upload_file(cmd)
else:
exit(0)