Python学习第41天(ftp习题实现day3)

今天完成了断点续传部分,即文件传输一半后断掉链接,重新继续发送的实现,以及进度条的实现,今天在测试的时候神兽configpraser模块的害,txt和cfg文件还是不一样啊,最终还是得抓紧看看configpraser模块的模式啊

先展示一下今天的主要两个部分,server端的主要逻辑区域server.py文件

import socketserver
import json
import configparser
from conf import settings
import os,sys

STATUS_CODE  = {
    250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}",
    251 : "Invalid cmd ",
    252 : "Invalid auth data",
    253 : "Wrong username or password",
    254 : "Passed authentication",
    255 : "Filename doesn't provided",
    256 : "File doesn't exist on server",
    257 : "ready to send file",
    258 : "md5 verification",

    800 : "the file exist,but not enough ,is continue? ",
    801 : "the file exist !",
    802 : " ready to receive datas",

    900 : "md5 valdate success"

}

class ServerHandler(socketserver.BaseRequestHandler):

    def handle(self):
        while True:
            data = self.request.recv(1024).strip()
            data = json.loads(data.decode('utf-8'))
            '''
            {'action' : 'auth' ,
             'username' : 'xiao',
             'password' : 123 }
            '''
        if data.get('action'):

            if hasattr(self,data.get('action')):
                func = getattr(self,data.get('action'))
                func(**data)
            else:
                print('func error')
                self.request.send('func error'.encode('utf-8'))
        else:
            print('Invalid cmd')
            self.request.send('Invalid cmd'.encode('utf-8'))

    def send_reponse(self , state_code):
        response = {'status_code':state_code}
        self.request.sendall((json.dumps(response)).encode('utf-8'))

    def auth(self,**data):
        username = data['username']
        password = data['password']

        user = self.authenticate(username,password)

        if user:
            self.send_reponse(254)
        else:
            self.send_reponse(253)


    def authenticate(self,user,pwd):
        cfg = configparser.ConfigParser()
        cfg.read(settings.ACCOUNT_PATH)

        if user in cfg.sections():
            if cfg[user]['password'] == pwd:
                self.user = user  # 登录成功之后保存了用户的登录信息
                self.mainPath = os.path.join(settings.BASE_DIR,'home',self.user)
                # print('passed authentication')  # 表示登录成功

                return user

    def put(self,**data):
        print('data',data)
        file_name = data.get('file_name')
        file_size = data.get('file_size')
        target_path = data.get('target_path')

        abs_path = os.path.join(self.mainPath,target_path,file_name)
        # 以上部分即已获得了想要保存文件在服务端的位置信息,可用于后续文件的打开

        has_received = 0
        if os.path.exists(abs_path):
        # 用于判断文件是否已经存在
            file_has_size = os.stat(abs_path).st_size
            if file_has_size < file_size:
                # 出现了断点续传的情况
                self.request.sendall('800'.encode('utf-8'))
                choice = self.request.recv(1024).decode('utf-8')
                if choice == 'Y':
                    self.request.sendall(str(file_has_size).encode('utf-8'))
                    has_received += file_has_size
                    f = open(abs_path,'ab')

                else:
                    f = open(abs_path,'wb')

                # 继续完善部分
            else:
                # 表示文件已存在,且比较完整,返回给客户端801的信息
                self.request.sendall('801'.encode('utf-8'))
                return
        else:
            self.request.sendall('802'.encode('utf-8'))
            f = open(abs_path , 'wb')

        while has_received < file_size:
            try:
                data = self.request.recv(1024)
            except Exception as e:
                break
            f.write(data)
            has_received += len(data)
        f.close()

ftp_client端

import socket
import optparse
import configparser
import json
import os
import sys

STATUS_CODE  = {
    250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}",
    251 : "Invalid cmd ",
    252 : "Invalid auth data",
    253 : "Wrong username or password",
    254 : "Passed authentication",
    255 : "Filename doesn't provided",
    256 : "File doesn't exist on server",
    257 : "ready to send file",
    258 : "md5 verification",

    800 : "the file exist,but not enough ,is continue? ",
    801 : "the file exist !",
    802 : " ready to receive datas",

    900 : "md5 valdate success"

}
# tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# tcp_client.connect(('127.0.0.1',8080))
# tcp_client.send('ok'.encode('utf-8'))
# 以上是easy模式下的

class ClientHandler():
    def __init__(self):
        self.op = optparse.OptionParser()

        self.op.add_option('-s','--server', dest = 'server')
        self.op.add_option('-P', '--port', dest='port')
        self.op.add_option('-u', '--username', dest='username')
        self.op.add_option('-p', '--password', dest='password')

        self.options,self.args = self.op.parse_args()

        self.verify_args(self.options,self.args)

        self.make_connection()

        self.mainPath = os.path.dirname(os.path.abspath(__file__))

        self.last = 0

    def verify_args(self,options,args ):
        # 对port端口进行校验
        server = options.server
        port = options.port
        # username = options.username
        # password = options.password

        if int(options.port) > 0 and int(port) < 65535:
            return True
        else:
            exit('the port is in 0~65535')

    def make_connection(self):
        self.sock = socket.socket()
        self.sock.connect((self.options.server, int(self.options.port)))
        print('已连接')

    def interractive(self):
        if self.authenticate():
            print('==========begin to interactive==========')
            cmd_info = input('[%s]'%self.user).strip()   #比如会输入 put 12.png images

            cmd_list = cmd_info.split('')
            if hasattr(self.cmd_list[0]):
                func = getattr(self,cmd_list[0])
                func(*cmd_list)

    def put(self, *cmd_list):
        # 传入命令: put 12.png images
        action, local_path, target_path = cmd_list
        local_path = os.path.join(self.mainPath , local_path)

        file_name = os.path.basename(local_path)
        file_size = os.stat(local_path).st_size

        data = {
            'action' : 'put',
            'file_name' : file_name,
            'file_size' : file_size,
            'target_path' : target_path
        }

        self.sock.sendall(json.dumps(data).encode('utf-8'))
        is_exist = self.sock.recv(1024).decode('utf-8')

        # 下面对接收到的信息进行处理(转入服务端的书写)
        has_sent = 0
        if is_exist == '800':
            # 表示文件存在不完整,即断点续传问题
            choice = input('文件已存在,但文件不完整(Y继续上传/N重新上传>>>').strip()
            if choice.upper() == 'Y':
                self.sock.sendall('Y'.encode('utf-8'))
                continue_position = self.sock.recv(1024).decode('utf-8')
                has_sent += int(continue_position)

            else:
                self.sock.sendall('N'.encode('utf-8'))

        elif is_exist == '801':
            # 表示文件已经存在,不用上传,所以就跳出put方法,重新转入输入命令那一行
            # 即 interractive 方法
            print("the file exist")
            return
        else:
            pass

        # 下面表示文件不存在的情况,就直接开始上传了
        f = open(local_path, "rb")
        f.seek(has_sent)

        while has_sent < file_size:
            data = f.read(1024)
            self.sock.sendall(data)
            has_sent += len(data)
            self.show_progress(has_sent, file_size)

        f.close()

        print("put success!")

    def show_progress(self,has,total):
        rate = float(has)/float(total)
        rate_num = int(100*rate)
        # if self.last != rate_num
        sys.stdout.write("%s%% %s\r"%(rate_num,"-"*rate_num))


    def authenticate(self):
        if self.options.username is None or self.options.password is None:
            username = input('username>>>')
            password = input('password>>>')
            print('ok')
            return self.get_auth_result(username,password)
        else:
            return self.get_auth_reult(self.options.username,self.options.password)

    def response(self):
        data = self.sock.recv(1024).decode('utf-8')
        data = json.loads(data)
        return data

    def get_auth_result(self,user ,pwd):
        data = {
            'action' : 'auth',
            'username' : user,
            'password' : pwd
        }

        self.sock.sendall((json.dumps(data)).encode('utf-8'))
        response = self.response()
        print('response是',response['status_code'])

        if response['status_code'] == 254:
            self.user = user
            print(STATUS_CODE[254])
            return True
        else:
            print(STATUS_CODE['status_code'])

ch = ClientHandler()

ch.interractive()

其他部分是完全没有变化的,今天时间有点紧,趁着晚上看看configpraser模块

import configparser

config=configparser.ConfigParser()
config.read('a.cfg')

#查看所有的标题
res=config.sections() #['section1', 'section2']
print(res)

#查看标题section1下所有key=value的key
options=config.options('section1')
print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']

#查看标题section1下所有key=value的(key,value)格式
item_list=config.items('section1')
print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]

#查看标题section1下user的值=>字符串格式
val=config.get('section1','user')
print(val) #egon

#查看标题section1下age的值=>整数格式
val1=config.getint('section1','age')
print(val1) #18

#查看标题section1下is_admin的值=>布尔值格式
val2=config.getboolean('section1','is_admin')
print(val2) #True

#查看标题section1下salary的值=>浮点型格式
val3=config.getfloat('section1','salary')
print(val3) #31.0

没找到比较清晰的介绍,目前还是一锅粥

明天再看看之前的教学视频吧,然后再补充,今天暂时就这样

猜你喜欢

转载自www.cnblogs.com/xiaoyaotx/p/12629989.html
今日推荐