zoukankan      html  css  js  c++  java
  • 网络编程基础【day09】:socket实现文件发送(六)

    本节内容

    1、概述

    2、文件下载实现

    3、MD5值校验

    一、概述

      我们如何利用socket去下载一个文件,整体思路是这样的:

    1. 读取文件名
    2. 检测文件是否存在
    3. 打开文件
    4. 检测文件大小
    5. 发送文件大小给客户端
    6. 等客户确认
    7. 开始边读边发数据
    8. 发送md5值给客户端校验

    友情提示:以下代码都是在Linux系统,并且是python3换将下实验的。

    二、文件下载实现

    2.1、服务端代码

    逻辑:获取命令和文件名->判断文件是否存在->打开文件->获取文件大小->发送文件大小给客户端->等待客户端确认->边读边发

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    import hashlib
    import socket,os
     
    server = socket.socket()
    server.bind(("localhost",9999))
    server.listen()
    while True:
        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()   #接收客户端发过来的命令和文件名
            print(filename)
            if os.path.isfile(filename):    #判断文件是否存在
                # m = hashlib.md5()
                with open(filename,"rb") as f:
                    file_size = os.stat(filename).st_size   #获取文件大小
                    conn.send( str(file_size).encode() ) #发送文件大小
                    conn.recv(1024)
                    for line in f:
                        #m.update(line)
                        conn.send(line)     #边读边发给客户端
                    #print("file md5",m.hexdigest())
            print("send done")
     
    server.close()

    2.2、客户端代码

    逻辑:判断是否是下载命令(get) ->发送下载命令和文件名 ->获取文件大小->发送确认信息->判断时候已经全部接收

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import  socket
     
    client = socket.socket()
    client.connect(("localhost",9999))
    while True:
        cmd = input(">>>:").strip()
        if len(cmd) == 0:continue
        if cmd.startswith("get"):
            client.send(cmd.encode())    #发送下载命令和文件名
            server_respose = client.recv(1024)    #接收文件大小
            print("server response:",server_respose)
            client.send("ready to recv file".encode())    #发送确认信息
            file_total_size = int(server_respose.decode())
            revived_size = 0   #初始化接收大小
            filename = cmd.split()[1]   #获取文件名
            with open(filename + ".new","wb") as f:
                while revived_size < file_total_size:    #判断接收大小和文件大小比较
                    data = client.recv(1024)
                    revived_size += len(data)   #接收大小
                    f.write(data)   #写入文件
                else:
                    print(file_total_size,revived_size)
                    print("file recv done")
    client.close()

    三、MD5值校验

    说明:上面只提到了怎么传输,我们在概述里面也提到了最后要用MD5值做校验,但是很显然没看到,下面我们就来说说怎么用MD5值做比较

    3.1、服务端

    说明:生成md5的对象->计算MD5值->生成16进制的形式->编码后发送给客户端

    ①代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import hashlib
    import socket,os
     
    server = socket.socket()
    server.bind(("localhost",9999))
    server.listen()
    while True:
        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()
            print(filename)
            if os.path.isfile(filename):
                = hashlib.md5()  #生成MD5的对象
                with open(filename,"rb") as f:
                    file_size = os.stat(filename).st_size
                    conn.send( str(file_size).encode() ) #send file size
                    conn.recv(1024)
                    for line in f:
                        m.update(line)  #计算md5值
                        conn.send(line)
                    print("file md5",m.hexdigest())
                conn.recv(1024)   #等待客户确认发送MD5值
                conn.send(m.hexdigest().encode())  #生成MD5值并且发送给客户端
            print("send done")
     
    server.close()

    ②改动的地方

    3.2、客户端

    说明:生成MD5值->计算接收的数据的MD5值->生成接收数据的MD5值16进制的形式->发送接收MD5值确认信息->接收客户端的MD5值->客户端和服务端的MD5值做比较

    ①代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    # __auther__ == zhangqigao
    import  socket,hashlib
     
    client = socket.socket()
    client.connect(("localhost",9999))
    while True:
        cmd = input(">>>:").strip()
        if len(cmd) == 0:continue
        if cmd.startswith("get"):
            client.send(cmd.encode())
            server_respose = client.recv(1024)
            print("server response:",server_respose)
            client.send("ready to recv file".encode())
            file_total_size = int(server_respose.decode())
            revived_size = 0
            filename = cmd.split()[1]
            = hashlib.md5()  #生成MD5对象
            with open(filename + ".new","wb") as f:
                while revived_size < file_total_size:
                    data = client.recv(1024)
                    revived_size += len(data)
                    m.update(data)   #计算数据接收的MD5值
                    f.write(data)
                else:
                    print(file_total_size,revived_size)
                    client_md5_vaule = m.hexdigest()  #生成接收数据的MD5值16进制形式
                    client.send("ready to recv file md5 value".encode())
                    server_md5_value = client.recv(1024)  #接收客户端的MD5值
                    if client_md5_vaule == server_md5_value.decode():  #客户端和服务端的MD5值做比较
                        print("file recv done")
                    else:
                        print(client_md5_vaule,server_md5_value.decode())
    client.close()

     ②改动地方

    总结:

    1. 上传和下载都是以客户端或者服务端加载文件,然后另外一边接收再写入文件。
    2. 解决粘包问题,在接收数据大小后需要等待确认信息。
    3. 看文件能都上传和下载,应该用MD5值去校验。
    4. 创建一个无限大的文件,请用:dd if=/dev/sda1 of=文件名,比如创建test.txt,则:dd if=/dev/sda1 of=test.txt
    5. 获取一个文件的大小:os.stat(文件名).st_size
  • 相关阅读:
    BZOJ 1854: [Scoi2010]游戏( 二分图最大匹配 )
    BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )
    BZOJ 3555: [Ctsc2014]企鹅QQ( hash )
    BZOJ 2226: [Spoj 5971] LCMSum( 数论 )
    BZOJ 3505: [Cqoi2014]数三角形( 组合数 )
    BZOJ 2510: 弱题( 矩阵快速幂 )
    BZOJ 1009: [HNOI2008]GT考试( dp + 矩阵快速幂 + kmp )
    BZOJ 1090: [SCOI2003]字符串折叠( 区间dp )
    HDU 2295 Radar dancing links 重复覆盖
    ZOJ 3209 Treasure Map dancing links
  • 原文地址:https://www.cnblogs.com/luoahong/p/9896130.html
Copyright © 2011-2022 走看看