zoukankan      html  css  js  c++  java
  • python 学习分享-实战篇高级的ftp

    #server代码
    import socketserver,os,hashlib
    
    Base_paht = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/db'
    
    class Server_ftp(socketserver.BaseRequestHandler):
        def handle(self):
            while 1:
                try:
                    self.username = self.request.recv(1024).strip()          #接受用户信息
                    if not self.username:continue
                    self.username_path = Base_paht + '/%s/' % self.username.decode()   #获取用户文件地址
                    print(self.username.decode(), '连接成功!')              #打印用户连接信息
                    self.request.send('连接服务器成功!'.encode())
                    while 1:
                        try:
                            self.data = self.request.recv(1024).strip()  #接受客户端命令
                            print('-->',self.data)
                            if not self.data :continue
                            print('{} wrote:'.format(self.client_address[0]),self.username)#打印ip及用户名称
                            cmd_dic = self.data.decode()   #命令编码
                            print('执行的命令为',cmd_dic)
                            if hasattr(self,cmd_dic + '_file'):   #判断是否存在这条命令
                                self.request.send('{}命令可以被执行'.format(cmd_dic).encode())
                                func = getattr(self,cmd_dic + '_file')    #反射
                                func()
                            else:
                                self.request.send('no'.encode())  #不存在发送错误信息
                        except ConnectionResetError as e:
                          #  print('err',e)
                            break
                except ConnectionResetError as e:
                    print(self.client_address[0],e)
                    break
        def get_file(self):
            filename = self.request.recv(1024).decode()
            print('客户端想要获取的文件名称为:',filename)
            if os.path.isfile(self.username_path + filename) :
                file_size = os.stat(self.username_path + filename).st_size  #确认文件大小
                self.request.send(str(file_size).encode())   #发送文件大小
                self.request.recv(1024)  #接收please give me
                f = open(self.username_path + filename,'rb')
                self.request.send(f.read())
                f.close()
                confirm = self.request.recv(1024).decode()
                print(confirm)
                f_1 = open(self.username_path + filename, 'rb')
                m2 = hashlib.md5()
                m2.update(f_1.read())
                f_1_m2 = m2.hexdigest()
                f.close()
                self.request.send(f_1_m2.encode())
                print(self.request.recv(1024).decode())
    
    
            else:
                self.request.send('no'.encode())   #如果文件不存在,发送no信息
        def put_file(self):
            filename = self.request.recv(1024).decode()
            if filename != 'no' :
                self.request.send('服务器收到文件名称!'.encode())
                file_size = self.request.recv(1024).decode()
                self.request.send('服务器收到文件大小为{}'.format(file_size).encode())
                f = open(self.username_path + filename,'wb')   #直接写入,如果有就覆盖
                confirm_size = 0
                while confirm_size < int(file_size):
                    if int(file_size) - confirm_size > 1024:  # 确保接受的准确性,拒绝粘包.
                        cal = 1024
                    else:
                        cal = int(file_size) - confirm_size
                    data = self.request.recv(cal)
                    confirm_size += len(data)
                    f.write(data)
                f.close()
                f_1 = open(self.username_path + filename,'rb')
                m2 = hashlib.md5()
                m2.update(f_1.read())
                f_1_m2 = m2.hexdigest()
                f_1.close()
                self.request.send(f_1_m2.encode())
                print(self.request.recv(1024).decode())
                self.request.send('{}上传完成'.format(filename).encode())  # 返回服务器信息,表示下载完成
    
            else:
                print('客户端传送错误文件名称!')
    
    
        def open_file(self):
            filename = self.request.recv(1024).decode()
            self.request.send('服务器收到目录名称!'.encode())
            self.request.recv(1024)  #防止粘包
            if os.path.exists(self.username_path + filename ):
                self.request.send('yes'.encode())
                self.request.recv(1024)
                path_dir = os.listdir(self.username_path+ filename)
                if path_dir == []:  # 如果为空
                    self.request.send('nothing'.encode())
                else:
                    self.request.send(str(path_dir).encode())
            else:
                self.request.send('no'.encode())
    
        def look_file(self):
            self.request.recv(1024)        #接收返回的数据,防止粘包
            path_dir = os.listdir(self.username_path)
            if path_dir == []:                       #如果为空
                self.request.send('nothing'.encode())
            else:
                self.request.send(str(path_dir).encode())
    
    
    
    
    
    if __name__ =='__main__':
        HOST,PORT = 'localhost' , 6969
        server = socketserver.ThreadingTCPServer((HOST,PORT),Server_ftp)
        print('----------->等待连接<------------')
        server.serve_forever()
    #client代码
    
    
    import socket,os,pickle,hashlib,sys
    
    
    
    floder_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/user_floder'
    user_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/conf'
    server_db_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/server_ftp/db/'
    
    
    class Scoket_ftp(object):
        # 客户端类
        def __init__(self):
            self.client = socket.socket()
    
        def client_user_register(self):
            #用户注册
            username = input('请输入用户名:').strip()
            password = input('请输入密码:').strip()
            if not os.path.exists(user_path + '/%s'%username) :
                pwd_md = hashlib.md5()       #md5加密用户密码
                pwd_md.update(bytes(password,encoding='utf-8'))
                pwd_save = pwd_md.hexdigest()
                pickle.dump({'username':username,'password':pwd_save},open(user_path + '/%s'%username,'wb'))
                os.makedirs(server_db_path + username)
                print('创建成功!')
            else:
                print('账户已经存在!')
    
    
        def client_user_login(self):
            #身份验证
            username = input('请输入用户名:').strip()
            password = input('请输入密码:').strip()
            if os.path.exists(user_path + '/%s'%username) :
                pwd_md = hashlib.md5()  # md5加密用户密码
                pwd_md.update(bytes(password,encoding='utf-8'))
                pwd_save = pwd_md.hexdigest()
                user_dic = pickle.load(open(user_path + '/%s'%username,'rb'))
                if username == user_dic['username'] and pwd_save == user_dic['password'] :
                    print('%s登录成功'%username)
                    return username
                else:
                    print('账户密码错误!')
                    return False
            else:
                print('账户密码错误!')
                return False
    
        def client_conn(self,ip_addr,port):
            #建立连接
            while 1:
                username = self.client_user_login()
                if username :
                    self.client.connect((ip_addr, port))
                    self.client.send(username.encode())
                    print(self.client.recv(1024).decode())
                    break
                else:
                    continue
    
    
        def help(self):
            #帮助信息
            print('''
            -----------help-----------
            look:查看当前目录下文件
            open foldername:打开文件夹
            get filename:下载文件
            put filename:上传文件
                    ''')
        def client_interaction(self):
            #交互
            while 1:
                self.help()
                cmd = input('请输入操作命令:').strip()
                if len(cmd.split()) == 1:  #判断命令行长度,如果是1的话,在判断输入
                    if cmd == 'look':
    
                        self.file_look()#使用look方法
                    elif cmd == 'exit':
                        self.file_exit()
                    else:
                        print('命令输入错误,请重新输入')
                        continue
                elif len(cmd.split()) == 2: #长度为2,证明是带有前面的语句的
                    cmd_option, filename = cmd.split()
                    if hasattr(self,'file_' + cmd_option):
                        func = getattr(self,'file_' +cmd_option)
                        func(filename)
                    else:
                        continue
                else:
                    continue
        def file_look(self):
            #查看
            self.client.send('look'.encode()) #发送方法
            print(self.client.recv(1024).decode())  # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
            self.client.send('please give me!'.encode())  # 自动发送给服务器
            print('文件目录:',self.client.recv(1024).decode()) #接收目录信息并打印
        def file_get(self,filename):
            #下载
            self.client.send('get'.encode())  #先发送方法
            print(self.client.recv(1024).decode())  #服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
            self.client.send(filename.encode())  #再发送文件名称
            confirm = self.client.recv(1024).decode()  #服务器确认文件是否存在,如果存在返回文件大小,如果不存在,返回no
            if confirm != 'no':
                self.client.send('please give me!'.encode())
                f = open(floder_path+'/'+filename,'wb')  #在下载文件夹中创建该文件(如果存在,则替换)
                confirm_cal = 0
                rate = 1
                while confirm_cal < int(confirm):
                    if int(confirm) - confirm_cal > 1024:   #确保接受的准确性,拒绝粘包.
                        cal = 1024
                    else:
                        cal = int(confirm) - confirm_cal
                    data = self.client.recv(cal)
                    confirm_cal += len(data)   #避免tcp拆包
                    f.write(data)
                    if int(confirm) > 102400:
                        if confirm_cal  > int(confirm)/100*(rate+1) and rate<= 100  :
                            rate += 1
                            r = '
    [%s]%d%%' % ("=" * rate, rate)
                            sys.stdout.write(r)
                            sys.stdout.flush()
                        else:
                            continue
                    else:
                        r = '[%s]%d%%'%('='*100,100)
                        sys.stdout.write(r)
                f.close()
                self.client.send('{}下载完成'.format(filename).encode())  # 返回服务器信息,表示下载完成
                f_1 = open(floder_path+'/'+filename,'rb')  #判断一致性
                m2 = hashlib.md5()
                m2.update(f_1.read())
                f_1_m2 = m2.hexdigest()
                f_1.close()
                f_1_m2_server = self.client.recv(1024).decode()
                if f_1_m2 == f_1_m2_server :
                    print('
    下载完成!')
                    self.client.send('客户端已经成功获取完整文件!'.encode())
                else:
                    print('传输异常')
                    self.client.send('客户端获取文件不完整或存在异常!'.encode())
            else:
                print('确认信息为no,文件可能不存在或有其他问题!')
    
        def file_put(self,filename):
            #上传文件
            self.client.send('put'.encode())  # 先发送方法
            print(self.client.recv(1024).decode())  # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
            if os.path.isfile(floder_path + '/' + filename):
                self.client.send(filename.encode())
                print(self.client.recv(1024).decode())  #拒绝粘包
                cal = os.stat(floder_path + '/' + filename).st_size #获取文件大小
                self.client.send(str(cal).encode()) #发送文件大小信息
                print(self.client.recv(1024).decode())  #获取反馈
                f = open(floder_path+'/'+filename,'rb')  #打开文件
                self.client.send(f.read())
                f.close()
                f_1 = open(floder_path + '/' + filename, 'rb')  #一致性校验
                m2 = hashlib.md5()
                m2.update(f_1.read())
                f_1_m2 = m2.hexdigest()
                f_1.close()
                f_1_m2_server = self.client.recv(1024).decode()
                if f_1_m2 == f_1_m2_server:
                    print('上传完成!')
                    self.client.send('客户端已经成功上传完整文件!'.encode())
                else:
                    print('传输异常')
                    self.client.send('客户端上传文件不完整或存在异常!'.encode())
                    print(self.client.recv(1024).decode())
            else:
                self.client.send('no'.encode())
                print('查无此文件')
        def file_open(self,filename):
            self.client.send('open'.encode())  # 先发送方法
            print(self.client.recv(1024).decode())  # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
            self.client.send(filename.encode()) #发送目录名称
            print(self.client.recv(1024).decode())
            self.client.send('防止粘包'.encode())
            confirm = self.client.recv(1024).decode()  # 服务器确认文件是否存在,如果存在返回yes,如果不存在,返回no
            if confirm != 'no':
                self.client.send('please give me!'.encode())  #自动发送给服务器
                file_dir = self.client.recv(1024).decode()
                print(file_dir)
    
            else:
                print('确认信息为no,目录可能不存在或有其他问题!')
    
    
    if __name__ == '__main__' :
        socket_ftp = Scoket_ftp()
        option = input('''
        ---------option----------
        1.创建用户
        2.登录
        3.退出
        ''').strip()
        if option == '1':
            socket_ftp.client_user_register()
        elif option == '2':
            socket_ftp.client_conn('localhost',6969)
    
            socket_ftp.client_interaction()
        elif option == '3':
            exit()
    
        else:
            print('wrong!')
            exit()
  • 相关阅读:
    python微信机器人
    爬取糗事百科,微信自动发送
    验证码破解
    [Python]机器学习【推荐】
    [Python]利用jieba.analyse进行 关键词 提取
    《将博客搬至CSDN》
    [极限测试]第一日进度
    [Python]调用百度API进行自然语言处理 标签、关键字 以及 词法分析
    学习进度报告【第三周】
    [Python]调用百度地图API对地点进行搜索,利用 JSON 返回纬度/行政区域编号
  • 原文地址:https://www.cnblogs.com/laay/p/7380503.html
Copyright © 2011-2022 走看看