python 网络编程-04 文件的传输
- 文件传输需要要hashlib 来验证文件的完整性
- 需要判断文件是否传输完成
文件完整性判断
import hashlib
md5 = hashlib.sha3_256()
md5.update(msg)
update 为追加完整性判断
md5.update(b'hello world')
与
md5.update(b'hello ')
md5.update(b'world')
hash 值完全相同
实现
proto.py
import struct
import hashlib
def sender(conn, msg: bytes):
pack_head = struct.pack('i', len(msg))
conn.send(pack_head)
conn.send(msg)
def receiver(conn) -> str:
length = struct.unpack('i', conn.recv(4))[0]
msg = ''
while True:
if length < 1024:
recv_msg = conn.recv(length)
msg += recv_msg.decode('utf-8')
break
else:
recv_msg = conn.recv(1024)
length -= 1024
msg = recv_msg.decode('utf-8')
return msg
class HashCheck:
def __init__(self):
self.md5 = hashlib.sha3_256()
def hash_md5(self, msg: bytes):
self.md5.update(msg)
server.py
import socket, traceback
from 文件传送与文件校验 import proto
def recv_file(c, filename):
md5obj = proto.HashCheck()
with open(filename, 'w') as f:
"""
1. 获取文件大小
2. 循环获取文件行
3. 追加验证文件完整性,并将文件行内容写入文件
4. 文件读完后 获取文件的MD5
5. 将获取的MD5与 计算的MD5 进行比较。
"""
size = proto.receiver(c)
file_size = int(size)
while True:
try:
line = proto.receiver(c)
md5obj.hash_md5(line.encode('utf-8'))
f.write(line)
file_size -= len(line)
# 文件接收完成
if file_size == 0:
break
except Exception as e:
print('连接异常')
c.close()
print(traceback.print_exc())
break
hash_md5 = proto.receiver(c)
if hash_md5 == md5obj.md5.hexdigest():
print('file receive success!')
else:
print('file receive failed!')
if __name__ == '__main__':
s = socket.socket()
s.bind(('127.0.0.1', 8000))
s.listen()
while True:
print('等待连接')
conn, addr = s.accept()
recv_file(conn, 'server1.txt')
client.py
import socket
import os
from 文件传送与文件校验 import proto
def send_file(filename):
s = socket.socket()
s.connect(('127.0.0.1', 8000))
# 获取文件大小
size = os.path.getsize(filename)
# 发送文件大小
proto.sender(s, str(size).encode('utf-8'))
with open(filename, 'rb') as f:
# 创建md5 的验证对象
md5obj = proto.HashCheck()
for line in f:
# 追加MD5 验证
md5obj.hash_md5(line)
# 发送文件行
proto.sender(s, line)
proto.sender(s, md5obj.md5.hexdigest().encode('utf-8'))
s.close()
if __name__ == '__main__':
send_file('client.txt')