FTP项目代码

直接上代码吧

整个程序包目录结构如下:

FTP:
  ftp_client
      client.py

  ftp_server
      bin
         start_server.py
      conf
         settings.py
      core
          main.py
          server.py
      home
          jack
      logger

ftp_server
1.start_server.py

import os,sys
PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(PATH)
from core import main

if __name__ == '__main__':
    main.ArgvHandler()

2.main.py

import optparse
import socketserver
import os
BASEPATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
from conf import settings
from core import server

class ArgvHandler():
    def __init__(self):
        self.op=optparse.OptionParser()
        options,args=self.op.parse_args()
        self.verification(options,args)

    def verification(self,options,args):
        if hasattr(self,args[0]):
            func=getattr(self,args[0])
            func()

    def start(self):
        s=socketserver.ThreadingTCPServer((settings.IP,settings.PORT),server.Myserver)
        print('服务端开始运行...')
        s.serve_forever()

    def stop(self):
        pass

3.server.py

import socketserver
import json
import os
user_pwd={
    'username':'jack',
    'password':'123'
}

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            data=self.request.recv(1024).decode('utf-8')
            data=json.loads(data)
            #拿到了字典
            if hasattr(self,data['action']):
                func=getattr(self,data['action'])
                func(**data)

    def put(self,**data):
        filesize=data['filesize']
        filepath=os.path.join(data['targetpath'],data['filename'])
        has_size=0
        if os.path.exists(filepath):
            now_has_size=os.stat(filepath).st_size
            if now_has_size < filesize:
                 #断点续传
                self.request.sendall('please_choice'.encode('utf-8'))
                choice=self.request.recv(1024).decode('utf-8')
                if choice == 'Y':
                    self.request.sendall(str(now_has_size).encode('utf-8'))
                    has_size+=now_has_size
                    f=open(filepath,'ab')
                else:
                    f = open(filepath, 'wb')
            else:
                self.request.sendall('ok'.encode('utf-8'))
        else:
            self.request.sendall('ready'.encode('utf-8'))
            f=open(filepath,'wb')

        while has_size < filesize:
            try:
                file_data=self.request.recv(1024)
            except Exception as e:
                break
            f.write(file_data)
            has_size+=len(file_data)
        f.close()

    def auth(self,**data):
        if data['username'] == user_pwd['username'] and data['password'] == user_pwd['password']:
            self.request.sendall('101'.encode('utf-8'))
        else:
            self.request.sendall('102'.encode('utf-8'))

4.settings.py

IP='127.0.0.1'
PORT=8080

ftp_client

1.client.py
import socket
import optparse
import sys,os
import json
import time
BASEPATH=os.path.dirname(os.path.abspath(__file__))
ServerPath=os.path.join(os.path.dirname(BASEPATH),'ftp_server')
FilePath=os.path.join(BASEPATH,'a.txt')
ip_port=('127.0.0.1',8080)

class Myclient:
    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.verity_port(self.options,self.args)
        self.connection()

    def verity_port(self,options,args):
        port=options.port
        if int(port)>0 and int(port)<65535:
            return True
        else:
            exit('端口不合法')
    def connection(self):
        print('客户端连接成功...')
        self.sock=socket.socket()
        self.sock.connect(ip_port)

    def auth(self):
        if self.authenticate():
            while True:
                cmd_msg=input('[%s]:' %self.user).strip()
                if not cmd_msg:continue
                if cmd_msg == 'quit':break
                cmd_list=cmd_msg.split()
                if hasattr(self,cmd_list[0]):
                    func=getattr(self,cmd_list[0])
                    func(*cmd_list)

    def put(self,*cmd_list):
        cmd_name,localfile,targetpath=cmd_list
        targetpath=os.path.join(ServerPath, 'home', self.user)
        filesize=os.stat(FilePath).st_size
        cmd_data={
            'action':cmd_name,
            'filename':localfile,
            'filesize':filesize,
            'targetpath':targetpath
        }
        # print(cmd_data['filename'],type(filesize),cmd_data['targetpath'])
        self.sock.sendall(json.dumps(cmd_data).encode('utf-8'))
        confirm_msg=self.sock.recv(1024).decode('utf-8')
        has_send=0
        if confirm_msg == 'ok':
            print('文件已存在,不需要上传了...')
            return
        elif confirm_msg == 'ready':
            print('开始全量上传...')
        elif confirm_msg == 'please_choice':
            choice=input('选择增量[y]还是全量[n]:[Y/N]').upper()
            if choice == 'Y':
                self.sock.sendall(choice.encode('utf-8'))
                choice_msg=self.sock.recv(1024).decode('utf-8')
                print('开始断点续传...')
                has_send = int(choice_msg)
            else:
                self.sock.sendall(choice.encode('utf-8'))
                print('开始整包覆盖...')

        f=open(FilePath, 'rb')
        f.seek(has_send)
        while has_send < filesize:
            file_data=f.read(1)
            self.sock.sendall(file_data)
            has_send+=len(file_data)
            self.show_process(has_send, filesize)
        f.close()
        print('传输结束')
        return
    def show_process(self,has,total):
        procent=int((has/total)*100)

        # print(procent)
        # sys.stdout.write('%s%%')
        sys.stdout.write('\r%s%% %s' %(procent,'#'*procent))
        time.sleep(0.1)
        sys.stdout.flush()

    def authenticate(self):
        username=self.options.username
        password=self.options.password
        if username is None or password is None:
            username=input('username:').strip()
            password=input('password:').strip()
            return self.verify_login(username, password)
        return self.verify_login(username,password)

    def verify_login(self,user,pwd):
        login_data={
            'action':'auth',
            'username':user,
            'password':pwd
        }
        login_data=json.dumps(login_data)
        self.sock.sendall(login_data.encode('utf-8'))
        verify_login_result=self.sock.recv(1024).decode('utf-8')
        if verify_login_result  == '101':
            self.user=user
            print('登录成功')
            return True
        else:
            print('用户名或密码错误,请重新输入!')
            return self.authenticate()


mc=Myclient()
mc.auth()

上面这段代码基本实现了登录验证、上传文件(整包上传和断点续传)以及进度条,但是不够完善,有些bug,比如重复执行put a.txt jack的命令会报错。
我没有找到为啥会这个样子,有待以后再找bug了。或者如有高手,请予赐教!

posted @ 2024-08-21 08:57  疯狂Python  阅读(81)  评论(0)    收藏  举报