• 基于tcp协议的登录,文件上传和下载


    ​ 【1】先登录,登录不成功循环登录,直到成功。登录成功后可以选择上传或者下载,上传有对应的文件,可选择上传哪个;下载有对应的文件,可选择下载哪个
    ​ 【2】登录,上传,下载时最好设置状态码,客户端和服务端约定好状态码,操作成功或者失败后,发送对应的状态码。注意,每一个操作要有唯一的状态码。
    ​ 比如: 登录成功 100 登录失败 101

    ​ 注册成功 102 注册失败 103

    ​ 上传成功 104 上传失败 105

    ​ 下载成功 106 下载失败 107

    ​ 【3】也可以用字典: dic = {'operate': 'login', 'result': res} res= True 或 False 表明要进行的操作,以及状态。比较直观
    ​ 【4】网络之间进行数据传递,最常用的就是json模块。传送一个字典
    ​ 【5】编程尽量少使用面向过程编程,多使用 函数 + 面向对象 编程
    ​ 【6】函数中都要用传参的方式,传入conn,sk等,不要用全局变量,便于文件拆分,进行进一步封装。不用全局变量 ,因为将来文件拆分后,全局变量就不能用了。
    ​ 【7】输入时,容易出错的地方,要进行异常处理(进一步优化)

    
    #server
        import os
        import sys
        import json
        import struct
        import socket
        import hashlib
    
        def my_send(conn,dic): #用于发送要 被下载的文件的信息(字典{'filename': filename, 'filesize': filesize});可下载文件列表
            str_dic = json.dumps(dic)
            b_dic = str_dic.encode('utf-8')
            mlen = struct.pack('i', len(b_dic))
            conn.send(mlen)  # 4个字节 表示字典/列表转成字节之后的长度
            conn.send(b_dic)  # 具体的字典数据
    
        def my_recv(conn): #用于接收将要上传文件的信息(字典形式)
            msg_len = conn.recv(4)
            dic_len = struct.unpack('i', msg_len)[0]
            msg = conn.recv(dic_len).decode('utf-8')
            msg = json.loads(msg)
            return msg
    
        def download(conn):
            g = os.walk(r'D:python22day30下载文件')
            file_lst = next(g)[2]  # ['11.jpg', '23.mp4', 'userinfo']
            my_send(conn,file_lst) #将文件列表发送到客户端
    
            while 1:
                num = conn.recv(1024).decode('utf-8')  # 选择要下载文件的序号
                if num.upper() == 'Q':break
                else:
                    path = r'D:python22day30下载文件'
                    abs_path = os.path.join(path,file_lst[int(num) - 1])
                    filename = os.path.basename(abs_path)
                    filesize = os.path.getsize(abs_path)
                    dic = {'filename': filename, 'filesize': filesize}
                    my_send(conn,dic) #发送用户选择要下载文件的信息,是一个字典
    
                    with open(abs_path, mode='rb') as f:
                        while filesize > 0:
                            content = f.read(1024)
                            filesize -= len(content)
                            conn.send(content)
    
        def upload(conn):
            while 1:
                msg = my_recv(conn)
                if msg['filename'] == None:break
                else:
                    with open(msg['filename'],'wb') as f:
                        while msg['filesize'] > 0:
                            content = conn.recv(1024)
                            msg['filesize'] -= len(content)
                            f.write(content)
                    conn.send('上传成功'.encode('utf-8'))
    
        def get_md5(username,password):
            md5 = hashlib.md5(username.encode('utf-8'))
            md5.update(password.encode('utf-8'))
            return md5.hexdigest()
    
        def login(conn):
            flag = True#用于跳出外层循环
            while flag:   #注意跳出多级循环问题
                msg = my_recv(conn)
                with open('userinfo') as f:
                    for line in f:
                        name, pwd = line.strip().split('|')
                        if name == msg['username'] and pwd == get_md5(name, msg['password']):
                            res, flag = True, False
                            break #跳出本级循环
                    else:
                        res = False
                    dic = {'operate': 'login', 'result': res} #状态码
                    my_send(conn, dic)
    	
        #主逻辑
        sk = socket.socket()
        sk.bind(('127.0.0.1',9002))
        sk.listen()
    
        conn,_ =sk.accept()
        login(conn)
        opt_dic = my_recv(conn)
        if hasattr(sys.modules[__name__],opt_dic['operate']): # __name__是变量名,以脚本运行时,对应的值为'__main__'。但是被当做模块导入时,名字为模块名。所以最好用__name__
            getattr(sys.modules[__name__],opt_dic['operate'])(conn)
    
        conn.close()
        sk.close()
        
    #client
        import os
        import sys
        import json
        import struct
        import socket
        def download(sk):  # 下载
            opt_dic = {'operate':'download'}
            my_send(sk,opt_dic) #将要进行的操作发送到服务端
    
            file_lst = my_recv(sk) #接收到来自服务端的文件列表
            while 1:
                for index, file in enumerate(file_lst, 1):
                    print(index,file)
                num = input('请输入要下载文件的序号(退出请按Q):').strip()
                if num.upper() == 'Q':
                    sk.send(num.encode('utf-8'))  # 发送q或Q
                    break
                elif num.isdigit() and 0 < int(num) <= len(file_lst):
                    sk.send(num.encode('utf-8'))  # 发送要下载文件的序号
                    msg = my_recv(sk) #接收要下载文件的信息,是一个字典
                    with open(msg['filename'], 'wb') as f:
                        while msg['filesize'] > 0:
                            content = sk.recv(1024)
                            msg['filesize'] -= len(content)
                            f.write(content)
                    print('下载成功')
                else:
                    print('输入有误')
    
        def upload(sk):
            opt_dic = {'operate': 'upload'}
            my_send(sk, opt_dic)
    
            g = os.walk(r'D:python22day30上传文件')
            file_lst = next(g)[2]  # ['11.jpg', '23.mp4', 'userinfo']
            while 1:
                for index, file in enumerate(file_lst, 1):
                    print(index, file)
                num = input('请输入要上传文件的序号(退出请按Q):').strip()
                if num.upper() == 'Q':
                    dic = {'filename': None, 'filesize': None}
                    my_send(sk, dic)
                    break
                elif num.isdigit() and 0 < int(num) <= len(file_lst):
                    path = r'D:python22day30上传文件'
                    abs_path = os.path.join(path, file_lst[int(num) - 1])
                    filename = os.path.basename(abs_path)
                    filesize = os.path.getsize(abs_path)
                    dic = {'filename': filename, 'filesize': filesize}
                    my_send(sk,dic)
    
                    with open(abs_path, mode='rb') as f:
                        while filesize > 0:
                            content = f.read(1024)
                            filesize -= len(content)
                            sk.send(content)
                    msg = sk.recv(1024).decode('utf-8')
                    print(msg)
    
        def my_recv(sk):     # 接收
            msg_len = sk.recv(4)
            dic_len = struct.unpack('i', msg_len)[0]
            msg = sk.recv(dic_len).decode('utf-8')
            msg = json.loads(msg)
            return msg
    
        def my_send(sk,dic):   # 发送
            str_dic = json.dumps(dic)
            b_dic = str_dic.encode('utf-8')
            mlen = struct.pack('i', len(b_dic))
            sk.send(mlen)  # 4个字节 表示字典转成字节之后的长度
            sk.send(b_dic)  # 具体的字典数据
    
        def login(sk):
            while True: #alex|aee949757a2e698417463d47acac93df
                usr = input('用户名:').strip() #alex
                pwd = input('密 码 :').strip() #3714
                dic = {'username': usr, 'password': pwd}
                my_send(sk, dic)
                ret = my_recv(sk)  #dic = {'operate': 'login', 'result': res} res=True 或 False
                if ret['operate'] == 'login' and ret['result']:
                    print('登录成功')
                    break
                else:
                    print('登录失败')
    
    	#主逻辑
        sk = socket.socket()
        sk.connect(('127.0.0.1',9002))
    
        login(sk)   # 登录
        opt_lst = ['upload','download']
        for index,opt in enumerate(opt_lst,1):
            print(index,opt)
        num = int(input('请选择您要操作的序号 :'))
        getattr(sys.modules[__name__],opt_lst[num-1])(sk)
    
        sk.close()
    
  • 相关阅读:
    .Net魔法堂:史上最全的ActiveX开发教程——发布篇
    .Net魔法堂:史上最全的ActiveX开发教程——开发篇
    JS魔法堂:浏览器模式和文档模式怎么玩?
    JS魔法堂:精确判断IE的文档模式by特征嗅探
    JS魔法堂:追忆那些原始的选择器
    意译:自调用函数表达式
    一起Polyfill系列:让Date识别ISO 8601日期时间格式
    一起Polyfill系列:Function.prototype.bind的四个阶段
    poco 线程库
    CDN理解<转>
  • 原文地址:https://www.cnblogs.com/xiaomage666/p/11073407.html
Copyright © 2020-2023  润新知