day8-socket实现文件发送

简述

客户端发送指令到服务端要下载文件,这时候服务器在发送文件给客户端之前的检查步骤有哪些?

服务器端检查流程

代码实现

服务器端

思路:解析命令=>检测文件是否存在=>打开文件=>检测文件大小=>发送文件大小给客户端=>等待客户端的确认信息=>开始边读边发

import socket,os,hashlib

server = socket.socket()
server.bind(("localhost",9972))
server.listen()
while True:
    conn,addr = server.accept()
    print("new conn:",addr)
    while True:
        data = conn.recv(1024)   
        if not data:
            print("客户端已断开")
            break
        cmd,filename = data.decode().split()  #接收客户端发过来的命令和文件名
        print(filename)
        if os.path.isfile(filename):  #判断文件是否存在
            with open(filename,"rb") as f1:
                file_total_size = os.stat(filename).st_size   #获取文件大小
                conn.send(str(file_total_size).encode())  #发送文件大小给客户端
                conn.recv(1024)   #接收客户端的ack信息
                for line in f1:
                    conn.send(line)   #边读边发文件给客户端
                f1.close()
    print("发送完成!")

server.close()

#运行输出
new conn: ('127.0.0.1', 62469)
t_test.py

客户端

思路:判断命令是否是下载动作=>发送命令给服务器端=>接收文件大小=>发送确认信息给客户端=>打开空文件=>循环接收文件并写入空文件

import socket

client = socket.socket()
client.connect(("localhost",9971))

while True:
    cmd_input = input(">>:")
    if len(cmd_input) == 0:
        continue
    if cmd_input.startswith("get"):
        client.send(cmd_input.encode())  #发送命令给服务器端
        server_response = client.recv(1024)  #接收文件大小
        print("server response:",server_response)
        client.send("准备接收文件".encode())   #发送确认信息给服务器端
        file_total_size = int(server_response.decode())
        recv_size = 0      #初始化文件大小为0
        filename = cmd_input.split()[1]   #获取文件名
        with open(filename+".new","wb") as f1:
            while recv_size < file_total_size:  #判断接收文件大小和文件总大小
                data = client.recv(1024)
                recv_size+=len(data)   #累加每次循环接收文件的大小
                f1.write(data)         #循环写入文件
                print(file_total_size,recv_size)
            else:
                print("文件接收完成")
                f1.close()
client.close()

#运行输出
>>:get t_test.py
server response: b'513'
513 475
513 513
文件接收完成
>>:

MD5值校验功能

我们在进行文件的下载时,为了保证文件的一致性,通常选择对文件做MD5的校验。

服务器端

思路:生成MD5对象=>对发送的数据计算MD5值=>生成16进制形式=>编码后发送给客户端

#运行输出
new conn: ('127.0.0.1', 62808)
socket_server_ssh.py
file MD5: 7e121fe6f7fbdd4dc4097a2e02744688

客户端

思路: 生成MD5对象=>对客户端接收的数据计算MD5值=>生成16进制形式=>接收服务端发来的原文件的MD5(16进制形式)=>判断接收的和服务器端发来的MD5是否相同

#运行输出
>>:get socket_server_ssh.py
server response: b'836'
836 22
836 215
836 341
836 549
836 723
836 804
836 836
文件接收完成
server file MD5: 7e121fe6f7fbdd4dc4097a2e02744688
client file MD5: 7e121fe6f7fbdd4dc4097a2e02744688
文件校验成功!
>>:

解析:程序实现了下载文件时对MD5进行校验的功能,但是由于服务端在#1和#2处存在2次连续的send,在测试运行中服务器端还是可能会出现粘包的问题,那么客户端也还是会接收服务器端发来的数据(包含文件数据和MD5),这就会造成文件下载错误,所以需要加入交互以解决粘包的问题。那么除了增加sleep和交互,还有别的方法解决粘包的问题吗?

注意:使用os.stat(该文件路径).st_size的大小和len(该文件bytes类型数据)的结果是一样的。

posted @ 2017-10-25 10:28  Mr.hu  阅读(106)  评论(0编辑  收藏  举报