1. 程式人生 > >python--》客戶端與服務端文件的下載

python--》客戶端與服務端文件的下載

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,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()

技術分享

技術分享

技術分享


python--》客戶端與服務端文件的下載