在介紹以前,咱們須要瞭解一個加密算法web
MD5 校驗和(checksum)經過對接收的傳輸數據執行散列運算來檢查數據的正確性。計算出的散列值拿來和隨數據傳輸的散列值比較。若是兩個值相同,說明傳輸的數據完整無誤、沒有被竄改過(前提是散列值沒有被竄改),從而能夠放心使用。算法
如客戶往咱們數據中心同步一個文件,該文件使用MD5校驗,那麼客戶在發送文件的同時會再發一個存有校驗碼的文件,咱們拿到該文件後作MD5運算,獲得的計算結果與客戶發送的校驗碼相比較,若是一致則認爲客戶發送的文件沒有出錯,不然認爲文件出錯須要從新發送。socket
另外值得注意的是,文件傳輸過程當中,還有一些粘包問題,這個問題,我會單獨列出博客來整理ide
敬請期待加密
同時因爲我的時間限制,上傳文件暫時移到明天(須要注意的是,這裏的文件指的是,txt,jpg,png等格式,而不是文件夾,關於文件夾,後面咱們會將它放到一個web上下載,這裏不作處理)code
首先老規矩:先創建server
server = socket.socket()blog
server.bind(('localhost',6666))圖片
server.listen()ip
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()