Python实现FTP简单的上传下载

client

import os
import json
import struct
import socket
import sys


def send_dic(sk1, dic, protocol=False):
    bytes_d = json.dumps(dic).encode('utf-8')  # json.dumps()将python值转化json格式的数据字符串
    if protocol:  # true按你找协议执行send,false直接发送不要协议
        len_b = len(bytes_d)
        len_dic = struct.pack('i', len_b)  # pack按照‘i‘格式把数据转化为字符串
        sk1.send(len_dic)
    else:
        pass

    sk1.send(bytes_d)


def recv_dic(sk1):
    str_dic = sk1.recv(1024).decode('utf-8')
    res_dic = json.loads(str_dic)  # json.loads()把json转换python的数据类型
    return res_dic


def get_user(opt='login'):
    d = {}
    a = 0
    while d == {} or a == 0:
        usr = input('用户名:').strip()  # 出去左右两边空格
        pwd = input('密码:').strip()
        if usr and pwd and opt == 'login':
            d = {'username': usr, 'password': pwd, 'operate': opt}
            a = 1
        elif usr and pwd and opt == 'register':
            pwd2 = input('密码确认:').strip()
            if pwd == pwd2:
                d = {'username': usr, 'password': pwd, 'operate': opt}
                a = 1
            else:
                print("两次密码不一致!")
                a = 1
                pass
        else:
            pass
    return d


def login(sk1):  # 登录
    d = get_user()
    if d: send_dic(sk1, d)
    res_dic = recv_dic(sk1)
    if res_dic['operate'] == 'login' and res_dic['flag']:
        print('登录成功')
        return True
    else:
        print('登录失败')
        return False


def register(sk1):  # 注册
    d = get_user('register')
    if d: send_dic(sk1, d)
    res_dic = recv_dic(sk1)
    print(res_dic)
    if res_dic['operate'] == 'register' and res_dic['flag']:
        print('注册成功')
        return True
    else:
        print('注册失败')
        return False


def upload(sk1):
    # 输入路径
    path = input('请输入要上传的文件路径:')
    if os.path.isfile(path):  # 判断是否是文件是则返回为真
        filename = os.path.basename(path)  # 返回文件名
        filesize = os.path.getsize(path)
        dic = {'filename': filename, 'filesize': filesize, 'operate': 'upload'}
        send_dic(sk1, dic, True)  # true表示这里使用自定义协议进行字典的传递
        with open(path, 'rb') as f:  # 文件读取,rb读二进制文件指针会放在文件开头
            while filesize > 0:
                content = f.read(1024)
                sk1.send(content)
                filesize -= len(content)
    else:
        pass


def download(sk1):
    # 输入路径
    path1 = input('请输入要下载的文件全名称:')
    path = "D:\FTP1\local\\" + path1
    if os.path.isfile(path):  # 判断是否是文件是则返回为真
        filename = os.path.basename(path)  # 返回文件名
        filesize = os.path.getsize(path)
        dic = {'filename': filename, 'filesize': filesize, 'operate': 'download'}
        send_dic(sk1, dic, True)  # true表示这里使用自定义协议进行字典的传递
        with open(path, 'rb') as f:  # 文件读取,rb读二进制文件且指针会放在文件开头
            while filesize > 0:
                content = f.read(1024)
                sk1.send(content)
                filesize -= len(content)
    else:
        pass


def quit(sk1):
    dic = {'operate': 'quit'}
    send_dic(sk1, dic, True)
    print("退出成功!")
    sys.exit()


def choose_opt(opt_lst1):
    num = '0'
    for index, opt in enumerate(opt_lst1, 1):
        print(index, opt[0])
    while num != '1' and num != '2':
        num = str(input('请输入要选择的操作序号 : '))
        if num != '1' and num != '2':
            print("输入错误!")
    num1 = int(num)
    func = opt_lst1[num1 - 1][1]  # func = login / register
    return func


def choose_opt1(opt_lst1):
    num = '0'
    for index, opt in enumerate(opt_lst1, 1):
        print(index, opt[0])
    while num != '1' and num != '2' and num != '3':
        num = str(input('请输入要选择的操作序号 : '))
        if num != '1' and num != '2' and num != '3':
            print("输入错误!")
        else:
            pass
    num1 = int(num)
    func = opt_lst1[num1 - 1][1]  # func = login / register
    return func


while True:
    sk = socket.socket()  # 生成socket连接对象
    sk.connect(('127.0.0.1', 9006))
    # 选择登录/注册
    opt_lst = [('登录', login), ('注册', register)]
    func = choose_opt(opt_lst)
    res = func(sk)

    while res:  # 登录注册成功才进行上传下载
        opt_lst2 = [('上传', upload), ('下载', download), ('退出', quit)]
        func = choose_opt1(opt_lst2)
        func(sk)

server

import os
import json  # 格式的转换
import struct
import hashlib  # 加密
import socketserver
import sys


class Auth:
    @staticmethod  # 静态方法,可以被类对象、子类对象等访问,只能访问属于类的属性,不能访问对象的属性
    def get_md5(opt_dic):  # defd定义函数
        md5 = hashlib.md5(opt_dic['username'].encode('utf-8'))  # md5不能被反解,加密是固定的一一对应的
        md5.update(opt_dic['password'].encode('utf-8'))  # 加密
        pwd = md5.hexdigest()  # 拿到字符串
        return pwd

    @classmethod  # 类方法
    def login(cls, opt_dic):
        # 把密码按照之前的规则进行加密
        pwd = cls.get_md5(opt_dic)
        # 和文件中的用户名和密码进行比对
        with open('userinfo', encoding='utf-8') as f:  # encoding,连接要使用utf—8编码
            for line in f:
                user, password = line.strip().split('|')
                if opt_dic['username'] == user and pwd == password:
                    dic = {'operate': 'login', 'flag': True}
                    return dic
                else:
                    pass

        dic = {'operate': 'login', 'flag': False}
        return dic

    @classmethod
    def register(cls, opt_dic):
        # 把密码按照自己的算法进行摘要
        pwd = cls.get_md5(opt_dic)
        # 把用户名和密码写在userinfo文件中
        with open('userinfo', 'a', encoding='utf-8') as f:
            a = f.write('%s|%s\n' % (opt_dic['username'], pwd))
            print(a)
        dic = {'operate': 'register', 'flag': True}
        return dic


class Myserver(socketserver.BaseRequestHandler):
    def mysend(self, dic):
        str_d = json.dumps(dic)
        self.request.send(str_d.encode('utf-8'))

    def myrecv(self, protocol=False, msg_len=1024):
        if protocol:
            bytes_len = self.request.recv(4)
            msg_len = struct.unpack('i', bytes_len)[0]
        else:
            pass

        msg = self.request.recv(msg_len)
        str_msg = msg.decode('utf-8')
        opt_dic = json.loads(str_msg)
        return opt_dic

    def handle(self):
        # conn==self.request
        opt_dic = self.myrecv()
        print(opt_dic)
        if hasattr(Auth, opt_dic['operate']):  # hasattr如果Auth有opt_dic的属性返回TURE,否则返回False
            dic = getattr(Auth, opt_dic['operate'])(opt_dic)  # getattr获取AUth的opt_dic属性
            self.mysend(dic)
        else:
            pass
        # 判断登陆的结果在dic中,如果登录注册成功,用户上传下载
        if dic['flag']:
            opt_dic = self.myrecv(True)
            if opt_dic['operate'] == 'upload':
                # 上传
                remote_path = 'D:\FTP1\local'
                filename = opt_dic['filename']
                file_path = os.path.join(remote_path, filename)  # 链接文件名
                with open(file_path, 'wb') as f:  # wb如果文件不存在则创建新文件,有则打开文件
                    while opt_dic['filesize'] > 0:
                        content = self.request.recv(1024)
                        f.write(content)
                        opt_dic['filesize'] -= len(content)
            elif opt_dic['operate'] == 'download':
                local_path = 'D:\FTP1\download'
                filename = opt_dic['filename']
                file_path = os.path.join(local_path, filename)  # 链接文件名
                with open(file_path, 'wb') as f:
                    while opt_dic['filesize'] > 0:
                        content = self.request.recv(1024)
                        f.write(content)
                        opt_dic['filesize'] -= len(content)
            else:
                os._exit(0)
        else:
            pass


sk = socketserver.ThreadingTCPServer(('127.0.0.1', 9006), Myserver)  # sk对象,ip地址和端口号
sk.serve_forever()

注意上传或下载的储存文件位置不同可能会引起报错,server端先运行,然后运行client。

求点赞!!!

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值