tcp实现登录验证、文件上传和下载

import socket
import struct
import json
import os
import sys

sc = socket.socket()
sc.connect(('127.0.0.1', 9998))
DOWNLOAD_PATH=r'F:\installsotf\python file\python全栈\每周作业\第六周作业升级-tcp登录验证-上传下载文件\download_file'

def send_user(user, pwd):  # 发送用户的账户和密码
    user_len = len(user.encode('utf-8'))
    leng = struct.pack('i', user_len)
    sc.send(leng)  # 用户的字节码长度
    sc.send(user.encode('utf-8'))  # 发送用户名的字节码

    pwd_len = len(pwd.encode('utf-8'))
    leng = struct.pack('i', pwd_len)
    sc.send(leng)  # 密码的字节码长度
    sc.send(pwd.encode('utf-8'))  # 密码的字节码

''' 接收服务端提供的各项功能:  '''

#接收服务端提供的功能字典。 dic = {'upload':'上传','download':'下载'}
def recv_dic(sc):#接收字典类型的数据,公共函数
    #接收字典的长度
    dic_len = sc.recv(4)
    leng=struct.unpack('i',dic_len)[0]
    #接收字节码字典
    dic = sc.recv(leng).decode('utf-8')
    dic=json.loads(dic)
    return dic
#发送字典类型数据的是函数,将dic={'file':file,'size':'size','user':user} 发送给对方
def send_dic(sc,dic):#发送字典类型的数据
    #将dic转成json格式,再编码
    dic=json.dumps(dic).encode('utf-8')
    len_dic = len(dic)
    leng=struct.pack('i',len_dic)
    sc.send(leng)
    sc.send(dic)
    return True
#显示服务端提供的功能
def show_func(dic):
    co=1
    for key in dic:
        print(f'{co}、{dic[key]}')
        co+=1
    return True
#通过这个函数获取到登录成功的用户名,为upload提供用户名
# def get_useranme():
#     return dic['user']

#给服务端发送字符串数据
def send_str(sc,msg):
    by_msg = msg.encode('utf-8')
    len_msg = len(by_msg)
    leng = struct.pack('i', len_msg)
    sc.send(leng)
    sc.send(by_msg)
    return True
 #接收服务端发来的普通数据(str)
def recv_str(sc):
     msg_len = sc.recv(4)
     leng = struct.unpack('i', msg_len)[0]
     # 接收str数据
     msg = sc.recv(leng).decode('utf-8')
     return msg

#接收下载文件的内容
def recv_file(sc,path,size):
    with open(path, 'wb')as fp:
        while size > 0:#加上struct模块来避免粘包
            strc_len = sc.recv(4)
            leng = struct.unpack('i',strc_len)[0]
            cont = sc.recv(leng)
            fp.write(cont)
            size -= leng


#从共享的文件中下载需要的文件到本地目录:
def download(sc):
    # 接收文件字典
    dic = recv_dic(sc)
    print(dic)
    print('------可下载的文件列表----:')
    for i in dic:
        print(f'{int(i) + 1}、{dic[i]}')
    while 1:
        num = input('输入文件序号进行下载):').strip()
        if num.isdecimal():
            # print(num, 77)
            num = int(num)
            if num > 0 and num <= len(dic):
                # 文件序号发送给服务端,代表要下载该文件
                send_str(sc, str(num - 1))
            else:
                print('无此文件序号。')
                continue

        else:
            print('输入有误。')
            continue
        #接收待下载的文件名和文件大小
        dic=recv_dic(sc)
        file=dic['file']
        size = dic['size']
        path=os.path.join(DOWNLOAD_PATH,file)
        #接收文件
        recv_file(sc,path,size)
        return True

#将文件上传给服务端
def upload(sc):
    while 1:
        path=input('输入上传文件的绝对路径:')
        if os.path.isfile(path):
            print(path)
            file = os.path.basename(path)
            size = os.path.getsize(path)
            dic = {'file':file,'size':size}
            #将dic发送给服务端
            send_dic(sc,dic)
            #将文件内容发送给服务端
            with open(path,'rb') as fp:
                #以rb打开就已经是字节类型,不需要进行编码
                while size>0:
                    cont = fp.read(1024)
                    leng=len(cont)
                    sc.send(cont)
                    size-=leng
            return True
        else:
            print('路径有问题或是个目录。')
            continue#文件不存在
#上传文件的:F:\installsotf\python file\python全栈\day30\login_file
def all_func(sc):
 # 写接收服务端功能的需要代码
    # 接收的dic = {'upload':'上传','download':'下载'}
    while 1:
        dic = recv_dic(sc)
        # 显示功能给客户端选择
        show_func(dic)
        choice = input('输入选择的序号(E/e退出):').strip()
        flag = choice #[1,上传 , 2,下载]
        if choice.isdecimal():
            choice = int(choice)
            fun_lis = list(dic.keys())#上传下载功能
            if choice > 0 and choice <= len(fun_lis):
                #将用户想实现的功能发送给服务端,download 或者 upload
                send_str(sc,fun_lis[choice-1])
                fun = getattr(sys.modules[__name__],fun_lis[choice-1])
                print(fun.__name__)
                #fun==download or upload
                flag=True
                while flag:
                    ret=fun(sc)#download
                    # #接收服务端发送的操作结果
                    ret=recv_str(sc)
                    fun_name = dic[fun_lis[choice-1]]
                    if ret =='True':
                        print(f'{fun_name}成功')
                    else:
                        print(f'{fun_name}失败')
                    stop=input('回车继续,(X/x退出下载):').strip()
                    if stop.upper()=='X':
                        send_str(sc,'break')
                        break
                    else:
                        send_str(sc,'continue')
        elif flag.upper()=='E':
            #告诉服务端退出功能选择
            send_str(sc,'exit')
            break
        else:
            #发送给服务端,说明不能接收文件操作
            send_str(sc,'not')
            print('输入有误。')

while 1:
    print('1、登录\n2、注册')
    chioce = input('输入的选择(q/Q退出):').strip()
    chioce_list = ['登录', '注册']
    if chioce == '1' or chioce == '2':
        user = input('输入用户名:').strip()
        pwd = input('输入密码:').strip()
        sc.send(chioce.encode('utf-8'))  # 发送选择给服务端
        send_user(user, pwd)
        ret = sc.recv(3).decode('utf-8')  # yes 或者 not
        if ret == 'yes':
            user_dic={'user':user}
            #注册或登录成功
            print(f'{chioce_list[int(chioce) - 1]}成功。')
            if chioce == '1':  # 代表用户是在登录,且登录成功了,那么就可以享受服务端提供的上传下载文件功能。
                '''添加客户端使用的功能的相应代码: 写成函数来实现。'''
                #调用主功能函数
                ret=all_func(sc)
        else:
            #注册或登录失败
            print(f'{chioce_list[int(chioce) - 1]}失败。')
    elif chioce.upper() == 'Q':
        # 发送Q给服务端,说明要退出。
        sc.send('Q'.encode('utf-8'))
        print('退出系统。')
        break
    else:
        print('输入有误。')
sc.close()

posted @ 2021-08-17 14:29  提笔按住它  阅读(259)  评论(0)    收藏  举报