天天看點

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

同理,這是用戶端

    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)

服務端大緻思路:

<a href="https://s1.51cto.com/oss/201711/15/09f753100746e0a921c363a050d26e62.png-wh_500x0-wm_3-wmp_4-s_3391020654.png" target="_blank"></a>

是以總的服務端代碼

import os,socket,hashlib

server.bind(('localhost',9999))

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

<a href="https://s5.51cto.com/oss/201711/15/69536ea6ea36d8d8d2b18756fdbd86f0.png-wh_500x0-wm_3-wmp_4-s_1452155190.png" target="_blank"></a>

用戶端代碼:

import socket,hashlib

client.connect(('localhost', 9999))

   cmd = input("&gt;&gt;&gt;:").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 &lt; file_total_size:

           if file_total_size - recv_size &gt; 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())

client.close()

<a href="https://s4.51cto.com/oss/201711/15/5507e250234ea7fb1723ef7bb92496f0.png-wh_500x0-wm_3-wmp_4-s_3346951819.png" target="_blank"></a>

<a href="https://s4.51cto.com/oss/201711/15/af0b77968ab298adf36621e83122f800.png-wh_500x0-wm_3-wmp_4-s_3827459950.png" target="_blank"></a>

<a href="https://s4.51cto.com/oss/201711/15/8c27a4f62e0f537e6a2444f7fc8992d1.png-wh_500x0-wm_3-wmp_4-s_2928388090.png" target="_blank"></a>

      本文轉自眉間雪 51CTO部落格,原文連結:http://blog.51cto.com/13348847/1982209,如需轉載請自行聯系原作者

繼續閱讀