Python Socketserver实现FTP文件上传下载代码实例

一、Socketserver实现FTP,文件上传、下载

目录结构

1、socketserver实现ftp文件上传下载,可以同时多用户登录、上传、下载

效果图:

二、上面只演示了下载,上传也是一样的,来不及演示了,上代码

1、客户端

​
    import socket,hashlib,os,json,sys,time
    class Ftpclient(object):
      def __init__(self):
        self.client = socket.socket()
    
      def connect(self,ip,port):
        self.client.connect((ip, port))
      def help(self):
        msg='''
        ls 
    
        pwd 
        
        cd ..
        
        get filename
        
        put filename
        
        '''
        print(msg)
    
    
      def interactive(self):
        """
        客户端入口
        :return:
        """
        while True:
          verify = self.authenticate() #服务器端认证
          if verify:
            while True:
              cmd = input('输入命令 >>').strip()
              if len(cmd) == 0:continue
              cmd_str = cmd.split()[0]
              if hasattr(self,'cmd_%s' %cmd_str):
                func = getattr(self,'cmd_%s' %cmd_str)
                func(cmd)
              else:
                self.help()
    
    
      def cmd_put(self,*args):
        """
        上传文件
        :param args:
        :return:
        """
        cmd_solit = args[0].split()
        start_time = self.alltime() # 开始时间
        if len(cmd_solit) > 1:
          filename = cmd_solit[1]
          if os.path.isfile(filename):
            filesize = os.stat(filename).st_size
            msg_dic = {
              'filename':filename,
              'size':filesize,
              'overridden':True,
              'action':cmd_solit[0]
            }
    
            self.client.send( json.dumps(msg_dic).encode('utf-8'))
            server_respinse=self.client.recv(1024) #防止粘包,等服务器确认返回
            print('文件开始上传',server_respinse)
            client_size = 0
            f = open(filename,'rb')
            for line in f:
              client_size += self.client.send(line)
              self.processBar(client_size,filesize) #进度条
            else:
              print('文件传输完毕,大小为 %s'%client_size)
              end_time = self.alltime()       # 结束时间
              print('本次上传花费了%s 秒'%self.alltime(end_time,start_time))
              f.close()
          else:
            print(filename,'文件不存在')
        else:
          print('输入有误!')
    
    
      def cmd_get(self,*args):
        """
        下载文件
        :param args:
        :return:
        """
        cmd_solit = args[0].split()
        start_time = self.alltime() # 开始时间
        filename = cmd_solit[1]
        if len(cmd_solit) > 1:
          msg_dic = {
            'filename': filename,
            'size': '',
            'overridden': True,
            'action': cmd_solit[0],
            'file_exist':''
          }
          self.client.send(json.dumps(msg_dic).encode('utf-8'))
          self.data = self.client.recv(1024).strip()
    
          cmd_dic = json.loads(self.data.decode('utf-8'))
          print(cmd_dic)
          if cmd_dic['file_exist']:
            if os.path.isfile(filename):
              f = open(filename + '.new', 'wb')
            else:
              f = open(filename, 'wb')
    
            self.client.send(b'200 ok')   #防止粘包,等服务器确认返回
            client_size = 0
            filesize = cmd_dic['size']
            m = hashlib.md5()
            while client_size < filesize:
              data=self.client.recv(1024)
              f.write(data)
              client_size +=len(data)
              m.update(data)
              self.processBar(client_size, filesize)
            else:
              print('下载完毕')
              end_time = self.alltime()  # 结束时间
              print('本次下载花费了%s 秒' % self.alltime(end_time, start_time))
              f.close()
              new_file_md5 = m.hexdigest()
              server_file_md5 = self.client.recv(1024)
              print('MD5', server_file_md5,new_file_md5)
    
          else:
            print('下载的 %s文件不存在'%filename)
    
        else:
          print('输入有误!')
    
    
      def cmd_dir(self,*arge):
        cmd_solit = arge[0].split()
        if len(cmd_solit) > 0:
          msg_dic = {
            'action': cmd_solit[0]
          }
          self.client.send(json.dumps(msg_dic).encode())
          cmd_dir = self.client.recv(1024)
          print(cmd_dir.decode())
    
        else:
          print('输入错误!')
    
    
    
      def alltime(self,*args):
        """
        计算上传、下载时间
        :param args:
        :return:
        """
        if args:
          return round(args[0] - args[1])
        else:
          return time.time()
    
    
      def processBar(self,num, total):
        """
        进度条
        :param num:文件总大小
        :param total: 已存入文件大小
        :return:
        """
        rate = num / total
        rate_num = int(rate * 100)
        if rate_num == 100:
          r = '\r%s>%d%%\n' % ('=' * int(rate_num /3), rate_num,)
        else:
          r = '\r%s>%d%%' % ('=' * int(rate_num /3), rate_num,)
        sys.stdout.write(r)
        sys.stdout.flush
    
    
      def authenticate(self):
        """
        用户加密认证
        :return:
        """
        username = input('输入用户名:>>')
        password = input('输入密码:>>')
        m = hashlib.md5()
        if len(username) > 0 and len(password) >0:
          username = ''.join(username.split())
          password = ''.join(password.split())
          m.update(username.encode('utf-8'))
          m.update(password.encode('utf-8'))
    
          m = {
            'username':username,
            'password':password,
            'md5':m.hexdigest()
          }
          self.client.send(json.dumps(m).encode('utf-8'))
          server_user_md5 = self.client.recv(1024).strip()
          print(server_user_md5.decode())
          if server_user_md5.decode() == 'success':
            print('登录成功!')
            return 'ok'
          else:
            print('用户名密码错误!')
        else:
          print('请输入用户名密码')
    
    f = Ftpclient()
    f.connect('localhost',9999)
    f.interactive()

2、服务器端

​
    import socketserver,json,os,hashlib,sys,paramiko
    import settings
    class Mysocketserver(socketserver.BaseRequestHandler):
      def put(self,*args):
        '''
        接受客户端上传文件
        :return:
        '''
        cmd_dic = args[0]
        filename = cmd_dic['filename'] #获取文件名
        filesize= cmd_dic['size']    #获取文件大小(字节)
    
        if os.path.isfile(filename):  #判断文件是否存在
          f = open(filename + '.new','wb')
        else:
          f = open(filename, 'wb')
    
        self.request.send(b'200 ok')  #防止粘包
        print('%s 文件开始上传' % self.client_address[0])
        received_size = 0
        while received_size < filesize:
          data = self.request.recv(1024)
          f.write(data)
          received_size += len(data)
        else:
          print('文件传输完毕',filename)
    
    
      def get(self, *args):
        '''
        客户端下载文件
        :return:
        '''
        msg_dic = {
          'filename': '',
          'size': '',
          'overridden': True,
          'action': '',
          'file_exist': ''
        }
    
        cmd_solit = args[0]
        filename = cmd_solit['filename']
        file_exist = os.path.isfile(filename)
        msg_dic['file_exist'] = file_exist
        print(file_exist)
        if file_exist:
          filesize = os.stat(filename).st_size
    
          msg_dic['filename'] = filename
          msg_dic['size'] = filesize
          msg_dic['action'] = cmd_solit['action']
    
          self.request.send(json.dumps(msg_dic).encode('utf-8'))
          server_respang = self.request.recv(1024) #防止粘包
          print('开始传输',server_respang)
          f = open(filename,'rb')
          m = hashlib.md5()
          for lien in f:
            m.update(lien)
            self.request.send(lien)
          else:
            print('传输完成')
            f.close()
            self.request.send(m.hexdigest().encode())
        else:
          print('文件不存在')
          self.request.send(json.dumps(msg_dic).encode('utf-8'))
      def client_authentication(self):
        """
        客户端认证
        :return:
        """
        self.client_user= self.request.recv(1024).strip()
        client_xinxi = json.loads(self.client_user.decode('utf-8'))
        try:
          with open(settings.school_db_file + client_xinxi['username'],'rb') as f:
            data = json.load(f)
            if data['md5'] == client_xinxi['md5']: #判断用户输入是否和服务器端MD5是否一致
              print('验证成功!')
              self.request.send('success'.encode())
              return 'success'
            else:
              self.request.send('error'.encode())
        except Exception as e:
          print('没有此用户',e)
          self.request.send('error'.encode())
      def dir(self,*args):
        """
        查看目录
        :param args:
        :return:
        """
        cmd_split = args[0]
        dd=cmd_split['action']
        result_os = os.popen(dd).read()
        self.request.send(result_os.encode())
    
      def handle(self):
        """
        服务器端入口
        :return:
        """
        while True:
          try:
            success = self.client_authentication()
            if success:
              self.data=self.request.recv(1024).strip()
              cmd_dic = json.loads(self.data.decode('utf-8'))
              action = cmd_dic['action']
              if hasattr(self,action):
                func = getattr(self,action)
                func(cmd_dic)
          except ConnectionResetError as e:
            print('连接断开',self.client_address[0])
            break
    if __name__ == '__main__':
    
      HOST,PORT='localhost',9999
      server=socketserver.ThreadingTCPServer((HOST,PORT),Mysocketserver)
      server.serve_forever()

settings.py 文件

​
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    DB_FILE = os.path.join(BASE_DIR, "data\\")
    school_db_file = os.path.join(DB_FILE)
    print(school_db_file)

data里两个做测试的文件,

alex 文件内容: {"username": "alex", "password": "123456", "md5": "94e4ccf5e2749b0bfe0428603738c0f9"}

kml123456文件内容: {"username": "kml123456", "password": "123456","md5": "a791650e70ce08896e3dafbaa7598c26"}

到这里差不多就没了,

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值