1. 程式人生 > 程式設計 >Python Socketserver實現FTP檔案上傳下載程式碼例項

Python Socketserver實現FTP檔案上傳下載程式碼例項

一、Socketserver實現FTP,檔案上傳、下載

  目錄結構

    Python Socketserver實現FTP檔案上傳下載程式碼例項

1、socketserver實現ftp檔案上傳下載,可以同時多使用者登入、上傳、下載

  效果圖:

  Python Socketserver實現FTP檔案上傳下載程式碼例項

Python Socketserver實現FTP檔案上傳下載程式碼例項

Python 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),)
    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,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': '','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","md5": "a791650e70ce08896e3dafbaa7598c26"}

到這裡差不多就沒了,

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。