在介绍之前,我们需要了解一个加密算法
MD5 校验和(checksum)通过对接收的传输数据执行散列运算来检查数据的正确性。计算出的散列值拿来和随数据传输的散列值比较。如果两个值相同,说明传输的数据完整无误、没有被窜改过(前提是散列值没有被窜改),从而可以放心使用。
如客户往我们数据中心同步一个文件,该文件使用MD5校验,那么客户在发送文件的同时会再发一个存有校验码的文件,我们拿到该文件后做MD5运算,得到的计算结果与客户发送的校验码相比较,如果一致则认为客户发送的文件没有出错,否则认为文件出错需要重新发送。
另外值得注意的是,文件传输过程中,还有一些粘包问题,这个问题,我会单独列出博客来整理
敬请期待
同时由于个人时间限制,上传文件暂时移到明天(需要注意的是,这里的文件指的是,txt,jpg,png等格式,而不是文件夹,关于文件夹,后面我们会将它放到一个web上下载,这里不做处理)
首先老规矩:先建立
server = socket.socket()
server.bind((‘localhost‘,6666))
server.listen()
while True:
conn, addr = server.accept()
print("new addr:",addr)
这个是相当格式化的部分,建立服务端,与客户端进行连接,并打印客户端的地址
client = socket.socket()
client.connect((‘localhost‘, 6666))
同理,这是客户端
while True:
cmd = input(">>>:").strip()
if len(cmd)==0:
continue
if cmd.startswith("get"):
filename = cmd.split()[1] #获取文件名
client.send(cmd.encode("utf-8"))#客户端把要下载的文件信息,交给服务端
这个上节已经分享到过,这里不作解释
这个是客户端要求你所输入的文件来源,输入格式是
get C:\Users\Public\Pictures\938876-20160611152927293-1786781422.png
有个同学,会有疑问cmd.split()[1],为什么会是一哇,不能是二或三吗
C:\Users\Public\Pictures\938876-20160611152927293-1786781422.png
注意,这里他的前面有一个空格,所以,可以提取后面的一位
while True:
data = conn.recv(1024)
if not data:
print("客户端已断开。。。")
break
cmd, filename = data.decode().split()#对信息进行解码,并除去空格,转化为两个字符串
print(filename)
服务端进行接受,其中 filename 为你的文件来源
if os.path.isfile(filename):
此步是为了判断,文件是否存在,如果存在,可以继续进行
f = open(filename,"rb")#打开文件
file_size = os.stat(filename).st_size
conn.send(str(file_size).encode("utf-8")) #发送文件大小
发送文件大小
客户端要开始接受文件大小了:
server_resp_size = client.recv(1024) #接收文件总的大小
file_total_size = int(server_resp_size.decode())
print("file size:", server_resp_size)#将文件大小进行打印
大家学到此处,可还有疑问?如果有疑问,欢迎咨询.
上面第一阶段,已经完成了,接下来就是正式的文件下载阶段了
client.send(b"ready to recv file...")#客户端,发消息,我要开始接收文件了
conn.recv(1024) #服务端,接收消息
服务端 for line in f:
m.update(line)
conn.send(line)
开始遍历文件,更新消息
客户端;f = open(filename+".new","wb"),创建一个以new格式的文件,用来接收服务
端发来的消息
客户端开始接受文件
while recv_size < file_total_size:#目的是为了防止黏包问题出现
if file_total_size - recv_size > 1024: #判断最后一次,之前接收大小设置为1024
size = 1024
else: #最后一次不足1024,则只接收文件剩余的部分,不包含MD5
size = file_total_size - recv_size
print("the last size:",size)
data = client.recv(size)
recv_size += len(data)
f.write(data)
服务端大致思路:
所以总的服务端代码
import os,socket,hashlib
server = socket.socket()
server.bind((‘localhost‘,9999))
server.listen()
while True:
conn, addr = server.accept()
print("new addr:",addr)
while True:
data = conn.recv(1024)
if not data:
print("客户端已断开。。。")
break
cmd, filename = data.decode().split()
print(filename)
if os.path.isfile(filename):
f = open(filename,"rb")
m = hashlib.md5()
file_size = os.stat(filename).st_size
conn.send(str(file_size).encode("utf-8")) #发送文件大小
conn.recv(1024) #等待回复
for line in f:
m.update(line)
conn.send(line)
print("file md5:",m.hexdigest())
f.close()
conn.send(m.hexdigest().encode("utf-8")) #发送MD5,与上面的“conn.send(line)”可能出现粘包
print("send done...")
server.close()
客户端代码:
import socket,hashlib
client = socket.socket()
client.connect((‘localhost‘, 9999))
while True:
cmd = input(">>>:").strip()
if len(cmd)==0:
continue
if cmd.startswith("get"):
filename = cmd.split()[1] #获取文件名
client.send(cmd.encode("utf-8"))
server_resp_size = client.recv(1024) #接收文件总的大小
file_total_size = int(server_resp_size.decode())
print("file size:", server_resp_size)
client.send(b"ready to recv file...")
f = open(filename+".new","wb")
recv_size = 0
m = hashlib.md5()
while recv_size < file_total_size:
if file_total_size - recv_size > 1024: #判断最后一次,之前接收大小设置为1024
size = 1024
else: #最后一次不足1024,则只接收文件剩余的部分,不包含MD5
size = file_total_size - recv_size
print("the last size:",size)
data = client.recv(size)
recv_size += len(data)
f.write(data)
m.update(data)
else:
client_md5 = m.hexdigest()
print("recv done...")
print("total size:", file_total_size, "had been received:", recv_size)
server_md5 = client.recv(1024)
print("server md5:", client_md5, "server md5:", server_md5.decode())
f.close()
client.close()