zoukankan      html  css  js  c++  java
  • Python3学习之路~8.4 利用socket实现文件传送+MD5校验

    利用socket实现文件传送,大约分为如下几步:

    1.读取文件名
    2.检测文件是否存在
    3.打开文件(别忘了最后关闭文件)
    4.检测文件大小
    5.发送文件大小给客户端
    6.等客户端确认
    7.开始边读边发数据
    8.md5验证

    实例1:实现步骤1-7

    运行代码

    #Author:Zheng Na
    
    #ftp服务端
    import socket
    import os
    
    server = socket.socket()
    
    server.bind(('localhost',6969))
    
    server.listen()
    
    while True:
        print("等待新客户端连接")
        conn,addr = server.accept()
        print("new conn: ",addr)
    
        while True:
            print("等待新指令")
            data = conn.recv(1024)
            if not data:
                print("客户端已断开")
                break
            cmd,filename = data.decode().split() # 1.读取文件名
            print("文件名:",filename)
            if os.path.isfile(filename): # 2.判断文件是否存在
                f = open(filename,'rb') # 3.打开文件
                file_size = os.stat(filename).st_size # 4.检测文件大小
                conn.send(str(file_size).encode()) # 5.发送文件大小给客户端
                print("等待客户ack应答...")
                client_final_ack = conn.recv(1024)  # 6.等待客户端确认
                print("客户应答:", client_final_ack.decode("UTF-8"))
                for line in f: # 7.开始边读边发数据
                    conn.send(line)
                f.close() # 关闭文件
                print("send done")
    
    server.close()
    ftp_socket_server1_simple.py
    #Author:Zheng Na
    
    #ftp客户端
    import socket
    
    client = socket.socket()
    
    client.connect(('localhost',6969))
    
    while True:
        cmd = input(">>: ").strip()
        if len(cmd) == 0: continue
        if cmd.startswith("get"):
            client.send(cmd.encode())
            server_response = client.recv(1024)
            print("server response: ",server_response)
            client.send(b'ready to recv file')
            file_total_size = int(server_response.decode())
            received_size = 0
            filename = cmd.split()[1]
            f = open(filename+'.new','wb')
            while received_size < file_total_size:
                data = client.recv(1024)
                received_size += len(data)
                f.write(data)
                # print(file_total_size,received_size)
            else:
                print("file recv done",file_total_size,received_size)
                f.close()
    
    client.close()
    ftp_socket_client1_simple.py

    输出结果

    [root@hadoop my-test-files]# python3 ftp_socket_server1_simple.py 
    等待新客户端连接
    new conn:  ('127.0.0.1', 34556)
    等待新指令
    文件名: test.txt
    等待客户ack应答...
    客户应答: ready to recv file
    send done
    等待新指令
    
    [root@hadoop my-test-files]# python3 ftp_socket_client1_simple.py 
    >>: get test.txt
    server response:  b'5028317'
    file recv done 5028317 5028317
    >>: 
    
    [root@hadoop my-test-files]# ll test*
    -rw-r--r-- 1 root root 5028317 12月  5 18:28 test.txt
    -rw-r--r-- 1 root root 5028317 12月  6 16:16 test.txt.new
    [root@hadoop my-test-files]# diff test.txt test.txt.new # 比较两个文件是否相同
    [root@hadoop my-test-files]# 
    输出结果

    实例2:实现步骤8:md5验证

    接下来,我们来给传送的文件进行MD5验证。

    思路:

    在服务端对要发送的文件进行MD5加密,得到一个16进制格式的hash1,发送给客户端;
    在客户端对接收到的文件进行MD5加密,得到一个hash2,并与hash1进行对比,如果相同,说明接收到的文件与服务器文件一致。
    由于文件比较大,可以打开文件后一行一行的进行md5加密,这样操作与整个文件一起加密效果是一致的。
    比如下面两段代码效果是一致的:

    # 代码1
    import hashlib
    hash = hashlib.md5()
    hash.update(b'Hello ')
    hash.update(b'World')
    print(hash.hexdigest()) # b10a8db164e0754105b7a99be72e3fe5
    
    # 代码2
    import hashlib
    hash = hashlib.md5()
    hash.update(b'Hello World')
    print(hash.hexdigest()) # b10a8db164e0754105b7a99be72e3fe5
    md5关键代码

    另外,由于服务端先发送了文件,再发送md5,为了防止两次send之间的粘包,我们可以在两次send之间加一段 客户确认 的代码,但是这次我们不这么做:
    由于在客户端接收文件时是循环接收,我们可以在接收文件前,加一个判断,判断最后一次接收文件的大小,如果小于1024字节,那么最后一次只接收文件最后剩下的部分。
    这样就可以保证最后接收的文件正好是发送文件的大小,从而不会导致粘包。

    运行代码

    #Author:Zheng Na
    
    #ftp服务端
    import socket
    import os
    import hashlib
    
    server = socket.socket()
    
    server.bind(('localhost',6969))
    
    server.listen()
    
    while True:
        print("等待新客户端连接")
        conn,addr = server.accept()
        print("new conn: ",addr)
    
        while True:
            print("等待新指令")
            data = conn.recv(1024)
            if not data:
                print("客户端已断开")
                break
            cmd,filename = data.decode().split() # 1.读取文件名
            print("文件名:",filename)
            if os.path.isfile(filename): # 2.判断文件是否存在
                f = open(filename,'rb') # 3.打开文件
                file_size = os.stat(filename).st_size # 4.检测文件大小
                conn.send(str(file_size).encode()) # 5.发送文件大小给客户端
                print("等待客户ack应答...")
                client_final_ack = conn.recv(1024)  # 6.等待客户端确认
                print("客户应答:", client_final_ack.decode("UTF-8"))
                m = hashlib.md5() # 8.1 md5
                for line in f: # 7.开始边读边发数据
                    m.update(line) # 8.2 md5
                    conn.send(line)
    
                server_file_md5 = m.hexdigest() # 8.3 md5
                print("server file md5: ",server_file_md5)
                conn.send(server_file_md5.encode()) # 8.4 md5
    
                f.close() # 关闭文件
                print("send done")
    
    server.close()
    ftp_socket_server2_md5.py
    #Author:Zheng Na
    
    #ftp客户端
    import socket
    import hashlib
    
    client = socket.socket()
    
    client.connect(('localhost',6969))
    
    while True:
        cmd = input(">>: ").strip()
        if len(cmd) == 0: continue
        if cmd.startswith("get"):
            client.send(cmd.encode())
            server_response = client.recv(1024)
            print("server response: ",server_response)
            client.send(b'ready to recv file')
            file_total_size = int(server_response.decode())
            received_size = 0
            filename = cmd.split()[1]
            f = open(filename+'.new','wb')
            m = hashlib.md5()
            while received_size < file_total_size: # 接收文件,防止粘包
                if file_total_size - received_size > 1024: # 要收的不止一次
                    size = 1024
                else:# 最后一次了,剩多少收多少
                    size = file_total_size -received_size
                    print("last receive:",size)
    
                data = client.recv(size)
                received_size += len(data)
                m.update(data)
                f.write(data)
                # print(file_total_size,received_size)
            else:
                client_file_md5 = m.hexdigest()
                print("file recv done",file_total_size,received_size)
                f.close()
    
            server_file_md5 = client.recv(1024).decode()
            print("server file md5: ",server_file_md5)
            print("client file md5: ",client_file_md5)
            if server_file_md5 == client_file_md5:
                print("server file md5 and client file md5 are same")
            else:
                print("server file md5 and client file md5 are different")
    
    client.close()
    ftp_socket_client2_md5.py

    注意:使用md5加密,运行结果会变慢。

    输出结果

    [root@hadoop my-test-files]# python3 ftp_socket_server2_md5.py 
    等待新客户端连接
    new conn:  ('127.0.0.1', 34566)
    等待新指令
    文件名: test.txt
    等待客户ack应答...
    客户应答: ready to recv file
    server file md5:  01e16e921c663c9e90246ddb7d9a746f
    send done
    等待新指令
    
    [root@hadoop my-test-files]# python3 ftp_socket_client2_md5.py 
    >>: get test.txt
    server response:  b'5028317'
    last receive: 335
    file recv done 5028317 5028317
    server file md5:  01e16e921c663c9e90246ddb7d9a746f
    client file md5:  01e16e921c663c9e90246ddb7d9a746f
    server file md5 and client file md5 are same
    >>: 
    
    [root@hadoop my-test-files]# ll test*
    -rw-r--r-- 1 root root 5028317 12月  5 18:28 test.txt
    -rw-r--r-- 1 root root 5028317 12月  6 17:44 test.txt.new
    [root@hadoop my-test-files]# diff test.txt test.txt.new 
    [root@hadoop my-test-files]# 
    输出结果
  • 相关阅读:
    Shell IFS
    Crontab
    linux awk
    free
    条件语句练习2
    条件语句练习
    打印菜单
    条件测试语法
    read 命令
    jQuery(实例)
  • 原文地址:https://www.cnblogs.com/zhengna/p/10079000.html
Copyright © 2011-2022 走看看