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


在介紹以前,咱們須要瞭解一個加密算法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)


服務端大體思路:


09f753100746e0a921c363a050d26e62.png-wh_










因此總的服務端代碼

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






69536ea6ea36d8d8d2b18756fdbd86f0.png-wh_


客戶端代碼:

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

5507e250234ea7fb1723ef7bb92496f0.png-wh_

af0b77968ab298adf36621e83122f800.png-wh_

8c27a4f62e0f537e6a2444f7fc8992d1.png-wh_

相關文章
相關標籤/搜索