python--》客戶端與服務端文件的下載
在介紹之前,我們需要了解一個加密算法
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,hashlibserver = 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,hashlibclient = 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()
python--》客戶端與服務端文件的下載