• 优酷系统


    涵盖内容:

    线程池,锁机制,session验证机制,简易版orm,大文件md5校验,数据库操作

    服务端目录

    conf

    import os
    
    BASE_PATH = os.path.dirname(
        os.path.dirname(__file__)
    )
    
    DOWNLOAD_PATH = os.path.join(
        BASE_PATH, 'download_files')
    settings

    db

    from orm.orm import Models, StringField, IntegerField
    
    
    # 用户表
    class User(Models):
        # 表名
        table_name = 'user'
        # 字段
        id = IntegerField(name='id', primary_key=True)
        name = StringField(name='name')
        #  pwd, is_vip, is_locked, user_type, register_time
        pwd = StringField(name='pwd')
        is_vip = IntegerField(name='is_vip')
        is_locked = IntegerField(name='is_locked')
        user_type = StringField(name='user_type')
        register_time = StringField(name='register_time')
    
    
    # 电影表
    class Movie(Models):
        # 表名
        table_name = 'movie'
        # 字段
        id = IntegerField(name='id', primary_key=True)
        name = StringField(name='name')
        # path, is_free, file_md5, user_id, is_delete, upload_time
        path = StringField(name='path')
        is_free = IntegerField(name='is_free')  # 1   0
        file_md5 = StringField(name='file_md5')
        user_id = IntegerField(name='user_id')
        is_delete = IntegerField(name='is_delete')
        upload_time = StringField(name='upload_time')
    
    
    # 公告表
    class Notice(Models):
        table_name = 'notice'
        # 字段
        id = IntegerField(name='id', primary_key=True)
        title = StringField(name='title')
        content = StringField(name='content')
        user_id = IntegerField(name='user_id')
        create_time = StringField(name='create_time')
    
    
    # 下载记录表
    class DownloadRecord(Models):
        table_name = 'download_record'
        # 字段
        id = IntegerField(name='id', primary_key=True)
        user_id = IntegerField(name='user_id')
        movie_id = IntegerField(name='movie_id')
        download_time = StringField(name='download_time')
    models.py
    user_online = {
        # addr: [session, user_id]
    }
    user_data

    download_files

    文本文件,添加下载电影

    interface

    from lib import common
    from db import models
    import os
    from conf import settings
    
    @common.login_auth
    def upload_movie_interface(client_back_dic, conn):
        print('炮王来交货啦!')
    
        # 确保电影名称是唯一的  随机字符串 + 电影名称
        movie_name = common.get_random_code() + client_back_dic.get('movie_name')  # .mp4
    
        movie_size = client_back_dic.get('file_size')
    
        movie_path = os.path.join(
            settings.DOWNLOAD_PATH, movie_name
        )
    
        # 1.接受上传的电影
        data_recv = 0
        with open(movie_path, 'wb') as f:
            while data_recv < movie_size:
                data = conn.recv(1024)
                f.write(data)
                data_recv += len(data)
    
        # 2.把电影数据保存到mysql中
        movie_obj = models.Movie(
            name=movie_name, file_md5=client_back_dic.get('file_md5'),
            is_free=client_back_dic.get('is_free'), is_delete=0,
            path=movie_path, user_id=client_back_dic.get('user_id'),
            upload_time=common.get_time()
        )
        movie_obj.save()
    
        send_dic = {
            'flag': True, 'msg': f'{client_back_dic.get("movie_name")}电影上传成功!'
        }
    
        common.send_data(send_dic, conn)
    
    
    @common.login_auth
    def check_movie_interface(client_back_dic, conn):
    
        file_md5 = client_back_dic.get('file_md5')
    
        movie_list = models.Movie.select(file_md5=file_md5)
    
        if movie_list:
    
            send_dic = {
                'flag': False, 'msg': '电影已存在!'
            }
    
        else:
    
            send_dic = {
                'flag': True, 'msg': '电影可以上传'
            }
    
        common.send_data(send_dic, conn)
    
    
    @common.login_auth
    def delete_movie_interface(client_back_dic, conn):
        movie_id = client_back_dic.get('movie_id')
        # 直接删除
        movie_obj = models.Movie.select(id=movie_id)[0]
        movie_obj.is_delete = 1
        # 调用更新方法
        movie_obj.sql_update()
    
        send_dic = {
            'flag': True, 'msg': '电影删除成功!'
        }
    
        common.send_data(send_dic, conn)
    
    
    @common.login_auth
    def put_notice_interface(client_back_dic, conn):
        title = client_back_dic.get('title')
        content = client_back_dic.get('content')
        user_id = client_back_dic.get('user_id')
        notice_obj = models.Notice(title=title, content=content, user_id=user_id,
                      create_time=common.get_time())
    
        notice_obj.save()
    
        send_dic = {
            'msg': '公告发布成功!'
        }
    
        common.send_data(send_dic, conn)
    admin_interface
    from db import models
    from lib import common, lock_file
    from db import user_data
    
    
    def register_interface(client_back_dic, conn):
    
        # 写业务逻辑
        # 1.判断用户名是否存在
        username = client_back_dic.get('username')
        # 通过用户名当作条件查询
        user_obj_list = models.User.select(name=username)
    
        # 若存在,给客户端返回数据, 告诉用户,用户已存在!
        if user_obj_list:
            send_dic = {'flag': False, 'msg': '用户已存在!'}
    
        # 若不存在,保存数据到MySQL数据库中, 返回注册成功给客户端
        else:
            password = client_back_dic.get('password')
            user_obj = models.User(
                name=username,
                #  pwd, is_vip, is_locked, user_type, register_time
                pwd=common.get_md5_pwd(password),
                is_vip=0,  # 0表示不是VIP, 1表示VIP
                is_locked=0,  # 0表示不锁定, 1表示锁定
                user_type=client_back_dic.get('user_type'),
                register_time=common.get_time())
    
            user_obj.save()
    
            send_dic = {'flag': True, 'msg': '注册成功'}
    
        common.send_data(send_dic, conn)
    
    
    def login_interface(client_back_dic, conn):
        # 执行login业务逻辑
        username = client_back_dic.get('username')
    
        # 1.根据用户名查询用户数据
        user_list = models.User.select(name=username)
    
        if not user_list:
            send_dic = {'flag': False, 'msg': '用户不存在'}
    
        else:
            user_obj = user_list[0]
            password = client_back_dic.get('password')
            # 1.判断客户端传入的密码与数据库中的密码是否相等
            if user_obj.pwd == common.get_md5_pwd(password):
    
                # 产生一个随机字符串,作为session值
                session = common.get_random_code()
                addr = client_back_dic.get('addr')
                # 保存session值到服务端,session + user_id一同保存到服务端本地
                # 使用锁写入数据
                lock_file.mutex.acquire()
                #  str(addr)
                user_data.user_online[addr] = [session, user_obj.id]
                lock_file.mutex.release()
    
                send_dic = {'flag': True, 'msg': '登录成功!',
                           'session': session, 'is_vip': user_obj.is_vip, 'new_notice': None}
    
                new_notice = get_new_notice_interface()
    
                if not new_notice:
                    pass
    
                else:
                    send_dic['new_notice'] = new_notice
    
            else:
                send_dic = {'flag': False, 'msg': '密码错误!'}
    
        common.send_data(send_dic, conn)
    
    
    # 获取电影接口
    @common.login_auth
    def get_movie_list_interface(client_back_dic, conn):
    
        # 获取所有电影对象
        movie_obj_list = models.Movie.select()
        # 添加未删除的电影列表
        back_movie_list = []
    
        if movie_obj_list:
    
            # 过滤已删除的电影
            for movie_obj in movie_obj_list:
    
                # 没有删除则返回
                if not movie_obj.is_delete:  # 1 代表删除
    
                    if client_back_dic.get('movie_type') == 'all':
                        back_movie_list.append(
                            # [电影名称、是否免费、电影ID]
                            [movie_obj.name,'免费' if movie_obj.is_free else "收费", movie_obj.id]
                        )
    
                    elif client_back_dic.get('movie_type') == 'free':
                        # 判断哪些电影是免费的
                        if movie_obj.is_free:
                            back_movie_list.append(
                                [movie_obj.name, '免费', movie_obj.id]
                            )
    
                    else:
                        if not movie_obj.is_free:
                            back_movie_list.append(
                                [movie_obj.name, '收费', movie_obj.id]
                            )
    
    
    
            if back_movie_list:
    
                send_dic = {'flag': True, 'back_movie_list': back_movie_list}
    
            else:
                send_dic = {'flag': False, 'msg': '没有电影!'}
        else:
    
            send_dic = {'flag': False, 'msg': '没有电影!'}
    
        common.send_data(send_dic, conn)
    
    
    
    def get_new_notice_interface():
    
        # 1.获取所有的公告
        notice_obj_list = models.Notice.select()  # 展示此处notice_obj_list的数据
        if not notice_obj_list:
            return False
    
        # 2.对公告的发布时间或者id进行排序,获取最新的一条公告
    
        notice_desc_list = sorted(
            # [notice_obj, notice_obj,notice_obj。。。]
            # 选择1:根据ID notice_obj_list, key=lambda notice_obj: notice_obj.id
            # 选择2:根据时间
            notice_obj_list, key=lambda notice_obj: notice_obj.create_time, reverse=True
        )
    
        new_notice = {
            'title': notice_desc_list[0].title,
            'content': notice_desc_list[0].content,
        }
        return new_notice
    common_interface
    from db import models
    from lib import common
    import os
    from conf import settings
    
    
    @common.login_auth
    def buy_vip_interface(client_back_dic, conn):
    
        user_id = client_back_dic.get('user_id')
    
        user_obj = models.User.select(id=user_id)[0]
        user_obj.is_vip = 1
        user_obj.sql_update()
    
        send_dic = {'flag': True, 'msg': '会员充值成功!'}
    
        common.send_data(send_dic, conn)
    
    
    @common.login_auth
    def download_movie_interface(client_back_dic, conn):
    
        movie_id = client_back_dic.get('movie_id')
        movie_name = client_back_dic.get('movie_name')
        movie_type = client_back_dic.get('movie_type')
        user_id = client_back_dic.get('user_id')
        # movie_obj = models.Movie.select(id=movie_id)[0]
        # movie_path = movie_obj.path
        movie_path = os.path.join(settings.DOWNLOAD_PATH, movie_name)
        movie_size = os.path.getsize(movie_path)
        send_dic = {
            'flag': True, 'msg': '准备下载', 'movie_size': movie_size
        }
        user_obj = models.User.select(id=user_id)[0]
    
        if movie_type == '免费':
            wait_time = 0
    
            if not user_obj.is_vip:
    
                wait_time = 20
    
            send_dic['wait_time'] = wait_time
    
        print(send_dic)
        common.send_data(send_dic, conn, movie_path)
    
        obj = models.DownloadRecord(user_id=user_id, movie_id=movie_id,
                              download_time=common.get_time())
        obj.save()
    
    
    @common.login_auth
    def check_download_record_interface(client_back_dic, conn):
        record_obj_list = models.DownloadRecord.select()
        user_id = client_back_dic.get('user_id')
    
        back_record_list = []
    
        if record_obj_list:
            for record_obj in record_obj_list:
                if record_obj.user_id == user_id:
    
                    # 获取当前用户下载电影记录的电影对象
                    movie_obj = models.Movie.select(id=record_obj.movie_id)[0]
    
                    back_record_list.append(
                        movie_obj.name
                    )
    
                else:
                    send_dic = {'flag': False, 'msg': '当前用户没有下载记录!'}
    
            send_dic = {
                'flag':True, 'record_list': back_record_list
            }
    
        else:
            send_dic = {'flag': False, 'msg': '没有任何下载记录!'}
    
        common.send_data(send_dic, conn)
    
    
    @common.login_auth
    def check_all_notice_interface(client_back_dic, conn):
    
        notice_obj_list = models.Notice.select()
    
        back_notice_list = []
    
        if notice_obj_list:
    
            for notice_obj in notice_obj_list:
                title = notice_obj.title
                content = notice_obj.content
                back_notice_list.append(
                    {'title': title, 'content': content}
                )
    
            send_dic = {'flag': True, 'back_notice_list': back_notice_list}
    
        else:
            send_dic = {'flag': False, 'msg': '没有公告!'}
    
        common.send_data(send_dic, conn)
    user_interface

    lib

    import time
    import hashlib
    import json
    import struct
    import uuid
    from functools import wraps
    from db import user_data
    
    
    def get_time():
    
        now_time = time.strftime('%Y-%m-%d %X')
    
        return now_time
    
    
    def get_md5_pwd(pwd):
        md = hashlib.md5()
    
        md.update(pwd.encode('utf-8'))
        md.update('虹桥炮王,Jason是也!'.encode('utf-8'))
    
        return md.hexdigest()
    
    
    
    def send_data(send_dic, conn, file=None):
        data_bytes = json.dumps(send_dic).encode('utf-8')
        headers = struct.pack('i', len(data_bytes))
        conn.send(headers)
        conn.send(data_bytes)
        if file:
            with open(file, 'rb') as f:
                for line in f:
                    conn.send(line)
    
    
    def get_random_code():
        # uuid可以产生一个世界上唯一的字符串
        md5 = hashlib.md5()
        md5.update(str(uuid.uuid4()).encode('utf-8'))
        return md5.hexdigest()
    
    
    # 登录认证装饰器
    def login_auth(func):
        @wraps(func)
        # (client_back_dic, conn) = args
        def inner(*args, **kwargs):
            # if args[0].get('session') == 服务端存放的session值:
            # # [session, user_id] = values
    
            addr = args[0].get('addr')
            # addr: [session, user_id]
    
            # [session, user_id]
            user_session = user_data.user_online.get(addr)
            if user_session:
                if args[0].get('session') == user_session[0]:
    
                    args[0]['user_id'] = user_session[1]
            #
            # for values in user_data.user_online.values():
            #     if args[0].get('session') == values[0]:
            #         # 添加到client_back_dic
            #         args[0]['user_id'] = values[1]  # user_id
    
            # 判断user_id是否存在
            if args[0].get('user_id'):
                func(*args, **kwargs)
    
            else:
                send_dic = {'flag': False, 'msg': '未登录,请去登录!'}
                # send_data(send_dic, conn)
    
                send_data(send_dic, args[1])
    
        return inner
    common.py
    mutex = None
    lock_file.py

    orm

    '''
    定义字段类
    '''
    from orm.mysql_control import Mysql
    
    
    class Field:
        def __init__(self, name, column_type, primary_key, default):
            self.name = name
            self.column_type = column_type
            self.primary_key = primary_key
            self.default = default
    
    
    # varchar
    class StringField(Field):
        def __init__(self, name, column_type='varchar(255)', primary_key=False, default=None):
            super().__init__(name, column_type, primary_key, default)
    
    
    # int
    class IntegerField(Field):
        def __init__(self, name, column_type='int', primary_key=False, default=0):
            super().__init__(name, column_type, primary_key, default)
    
    
    # 元类控制表模型类的创建
    class OrmMetaClass(type):
    
        # 类名, 类的基类, 类的名称空间
        def __new__(cls, class_name, class_bases, class_attr):
            # print(class_name, class_bases, class_attr)
            # 1.过滤Models类
            if class_name == 'Models':
                return type.__new__(cls, class_name, class_bases, class_attr)
    
            # 2.控制模型表中: 表名, 主键, 表的字段
            # 如果模型表类中没有定义table_name,把类名当做表名
    
            # 获取表名
            table_name = class_attr.get('table_name', class_name)  # user_info, User
    
            # 3.判断是否只有一个主键
            primary_key = None
    
            # 用来存放所有的表字段, 存不是目的,目的是为了取值方便
            mappings = {}
    
            '''
            __main__: xxxx
            'id': <__main__.IntegerField object at 0x000001E067D48B00>, 
            'name': <__main__.StringField object at 0x000001E067D48AC8>}
            '''
            for key, value in class_attr.items():
    
                # 判断value是否是字段类的对象
                if isinstance(value, Field):
    
                    # 把所有字段都添加到mappings中
                    mappings[key] = value
    
                    if value.primary_key:
    
                        if primary_key:
                            raise TypeError('主键只能有一个')
    
                        # 获取主键
                        primary_key = value.name
    
            # 删除class_attr中与mappings重复的属性, 节省资源
            for key in mappings.keys():
                class_attr.pop(key)
    
            # 判断是否有主键
            if not primary_key:
                raise TypeError('必须要有一个主键')
    
            class_attr['table_name'] = table_name
            class_attr['primary_key'] = primary_key
            class_attr['mappings'] = mappings
            '''
                   'table_name': table_name
                   'primary_key': primary_key
                   'mappings': {'id': <__main__.IntegerField object at 0x000001E067D48B00>,
                                'name': <__main__.StringField object at 0x000001E067D48AC8>}
                                }
           '''
            return type.__new__(cls, class_name, class_bases, class_attr)
    
    
    # 继承字典类,
    class Models(dict, metaclass=OrmMetaClass):
        def __init__(self, **kwargs):
            # print(kwargs)  # 接收关键字参数
            super().__init__(**kwargs)
    
        # 在对象.属性没有的时候触发
        def __getattr__(self, item):
            # print(item)
            return self.get(item, '没有这个key')
    
        # 在对象.属性 = 属性值 时触发
        def __setattr__(self, key, value):
    
            # 字典赋值操作
            self[key] = value
    
        #
        @classmethod
        def select(cls, **kwargs):
    
            # 获取数据库链接对象
            ms = Mysql()
    
            # 若没有kwargs代表没有条件查询
            if not kwargs:
                # select * from table;
                sql = 'select * from %s' % cls.table_name
    
                res = ms.my_select(sql)
    
            # 若有kwargs代表有条件
            else:
                # print(kwargs)  # {id:1}
                key = list(kwargs.keys())[0]  # id
                value = kwargs.get(key)  # 1
    
                # select * from table where id=1;
                sql = 'select * from %s where %s=?' % (
                    cls.table_name, key
                )
    
                sql = sql.replace('?', '%s')
    
                res = ms.my_select(sql, value)
    
            if res:
                # [{},{}, {}]   ---->  [obj1, obj2, obj3]
                # 把mysql返回来的 列表套 字典 ---> 列表套 对象
                # l1 = []
                # # 遍历mysql返回所有的字典
                # for d in res:
                #     # 把每一个字典传给cls实例化成一个个的r1对象
                #     r1 = cls(**d)
                #     # 追加到l1列表中
                #     l1.append(r1)
    
                return [cls(**result) for result in res]
    
        # 插入
        def save(self):
            ms = Mysql()
            # insert into table(x,x,x) values(x,x,x);
    
            # 字段名
            fields = []
            # 字段的值
            values = []
            # 存放对应字段的?号
            args = []
    
            for k, v in self.mappings.items():
                # 把主键过滤掉
                if not v.primary_key:
                    fields.append(
                        v.name
                    )
                    values.append(
                        getattr(self, v.name, v.default)
                    )
                    args.append('?')
    
            # insert into table(x,x,x) values(?, ?, ?);
            sql = 'insert into %s(%s) values(%s)' % (
                self.table_name, ','.join(fields), ','.join(args)
            )
    
            sql = sql.replace('?', '%s')
    
            ms.my_execute(sql, values)
    
        # 更新
        def sql_update(self):。
            ms = Mysql()
    
            fields = []
            primary_key = None
            values = []
    
            for k, v in self.mappings.items():
                # 获取主键的值
                if v.primary_key:
                    primary_key = getattr(self, v.name, v.default)
    
                else:
    
                    # 获取 字段名=?, 字段名=?,字段名=?
                    fields.append(
                        v.name + '=?'
                    )
    
                    # 获取所有字段的值
                    values.append(
                        getattr(self, v.name, v.default)
                    )
    
            # update table set %s=?,... where id=1;  把主键当做where条件
            sql = 'update %s set %s where %s=%s' % (
                self.table_name, ','.join(fields), self.primary_key, primary_key
            )
    
            # print(sql)  # update User set name=? where id=3
    
            sql = sql.replace('?', '%s')
    
            ms.my_execute(sql, values)
    
    
    # User, Movie, Notice
    # 表模型类
    class User(Models):
        # table_name = 'user_info'
        id = IntegerField(name='id', primary_key=True)
        name = StringField(name='name')
        # pwd = StringField(name='pwd')
    
    
    class Movie(Models):
        id = IntegerField(name='id', primary_key=True)
        pass
    
    
    # # # User('出入任意个数的关键字参数')
    # user_obj = User()  # user_obj--->dict
    # user_obj.name = 'xxxx'
    
    # if __name__ == '__main__':
    #     res = User.select(name='jason_sb')[0]
    #     print(res)
    #
    #     # res.name = 'jason_sb'
    #     #
    #     # res.sql_update()
    #
    #     # user_obj = User(name='egon')
    #     # user_obj.save()
    #
    # '''
    # 表:
    #     表名, 只有一个唯一的主键, 字段(必须是Field的字段)
    #
    # 元类:
    #     通过元类控制类的创建.
    # '''
    #
    # # class Movie:
    # #     def __init__(self, movie_name, movie_type):
    # #         self.movie_name = movie_name
    # #         self.movie_type = movie_type
    # #
    # #
    # # class Notice:
    # #     def __init__(self, title, content):
    # #         self.title = title
    # #         self.content = content
    #
    # '''
    # 问题1: 所有表类都要写__init__, 继承一个父类
    # 问题2: 可以接收任意个数以及任意名字的关键字参数. 继承python中的字典对象.
    # '''
    #
    # # if __name__ == '__main__':
    # #     # d1 = dict({'name': 'tank'})
    # #     # d2 = dict(name='tank2')
    # #     # print(d1)
    # #     # print(d2)
    # #
    # #     d3 = Models(name='jason')
    # #     # print(d3)
    # #     # print(d3.get('name'))
    # #     # print(d3['name'])
    # #     # print(d3.name)
    # #     # d3.name = 'tank'
    # #     # d3.pwd = '123'
    # #     # print(d3.name)
    # #     # print(d3)
    # #     print(d3.name)  # None
    # #
    # #     d3.pwd = '123'
    # #     print(d3.pwd)
    # #     print(d3)
    
    
    if __name__ == '__main__':
        # 查看所有
        # res = User.select()
        # print(res)
    
        # 根据查询条件查询
        res = User.select(name='json_egon_sb')
        print(res)
    #
    #     # 更新
    #     # user_obj = res[0]
    #     # user_obj.name = 'jason_sb_sb'
    #     # user_obj.sql_update()  # {'id': 3, 'name': 'jason_sb'}
    #
    #     # 插入
    #     # user_obj = User(name='json_egon_sb')
    # #     # user_obj.save()
    orm.py
    import pymysql
    from orm.db_pool import POOL
    
    
    class Mysql:
    
        def __init__(self):
            # 建立链接
            self.conn = POOL.connection()
    
            # 获取游标
            self.cursor = self.conn.cursor(
                pymysql.cursors.DictCursor
            )
    
        # 关闭游标链接方法
        def close_db(self):
            self.cursor.close()
            self.conn.close()
    
        # 查看
        def my_select(self, sql, args=None):
    
            self.cursor.execute(sql, args)
    
            res = self.cursor.fetchall()
            # [{}, {}, {}]
            # print(res)
            return res
    
        # 提交
        def my_execute(self, sql, args):
            try:
                # 把insert , update...一系列sql提交到mysql中
                self.cursor.execute(sql, args)
    
            except Exception as e:
                print(e)
    mysql_control.py
    from DBUtils.PooledDB import PooledDB
    import pymysql
    # pip3 install DBUtils
    
    POOL = PooledDB(
        creator=pymysql,  # 使用链接数据库的模块
        maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数
        mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
        maxcached=5,  # 链接池中最多闲置的链接,0和None不限制
        maxshared=3,
        # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
        blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
        maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制
        setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
        ping=0,
        # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
        host='127.0.0.1',
        port=3306,
        user='root',
        password='qinsungui',
        database='youku_demo11',
        charset='utf8',
        autocommit='True'
    )
    db_pool.py

    tcp_server

    import socket
    import struct
    import json
    from interface import common_interface
    from interface import admin_interface
    from interface import user_interface
    from concurrent.futures import ThreadPoolExecutor
    from threading import Lock
    from lib import lock_file
    from db import user_data
    
    lock = Lock()
    
    lock_file.mutex = lock
    
    
    func_dic = {
        'register': common_interface.register_interface,
        'login': common_interface.login_interface,
        # 查看电影是否存在接口
        'check_movie': admin_interface.check_movie_interface,
    
        'upload_movie': admin_interface.upload_movie_interface,
    
        # 获取电影列表接口
        'get_movie_list': common_interface.get_movie_list_interface,
    
        'delete_movie': admin_interface.delete_movie_interface,
    
        'put_notice': admin_interface.put_notice_interface,
    
        # 普通用户功能
        'buy_vip': user_interface.buy_vip_interface,
        'download_movie': user_interface.download_movie_interface,
        'check_download_record': user_interface.check_download_record_interface,
        'check_all_notice': user_interface.check_all_notice_interface,
    }
    
    
    class SocketServer:
        def __init__(self):
            self.server = socket.socket()
            self.server.bind(
                ('127.0.0.1', 9527)
            )
            self.server.listen(5)
            self.pool = ThreadPoolExecutor(50)
    
    
        def run(self):
            print('启动服务端...')
            while True:
                conn, addr = self.server.accept()  # 1 2 3
                # 通过self.pool 线程池异步提交任务(working)
                # self.pool.submit(函数对象, 传递给函数对象的参数1, 参数2)  # 1 2 3
                self.pool.submit(self.working, conn, addr)  # 1 2 3
    
        # 任务分发
        def dispatcher(self, client_back_dic, conn):
            # # 判断功能的类型
            # if client_back_dic.get('type') == 'register':
            #     common_interface.register_interface(client_back_dic, conn)
            #
            # elif client_back_dic.get('type') == 'login':
            #     common_interface.login_interface(client_back_dic, conn)
    
            # 通过_type变量接受客户端选择的功能类型
            _type = client_back_dic.get('type')  # login
    
            if _type in func_dic:  # register
                func_dic.get(_type)(client_back_dic, conn)
    
        # 用于执行客户端连接任务
        def working(self,  conn, addr):
            while True:
                try:
                    # 每一个客户端访问服务端都会经过此处
                    # 此处用于接收客户端传入的数据
                    headers = conn.recv(4)
                    data_len = struct.unpack('i', headers)[0]
                    data_bytes = conn.recv(data_len)
                    client_back_dic = json.loads(data_bytes.decode('utf-8'))
                    # 把每个用户的addr一并赋值给客户端传过来的字典
                    client_back_dic['addr'] = str(addr)
                    # 把客户端传递过来的字典与conn传给dispatcher执行
                    self.dispatcher(client_back_dic, conn)
    
                except Exception as e:
                    print(e)
                    lock.acquire()
                    user_data.user_online.pop(str(addr))
                    lock.release()
                    conn.close()
                    break
    socket_server

    readme

    start.py

    import os
    import sys
    sys.path.append(
        os.path.dirname(__file__)
    )
    from tcp_server.socket_server import SocketServer
    
    
    if __name__ == '__main__':
        server = SocketServer()  # __init
    
        server.run()  #
    start.py

    客户端目录

    conf

    import os
    
    BASE_PATH = os.path.dirname(
        os.path.dirname(__file__))
    
    UPLOAD_FILES = os.path.join(
        BASE_PATH, 'upload_files')
    
    DOWNLOAD_FILES = os.path.join(
        BASE_PATH, 'download_files')
    settings.py

    core

    from tcp_client import socket_client
    from lib import common
    import os
    from conf import settings
    user_info = {
        'cookies': None
    }
    
    def register(client):
        while True:
            username = input('请输入用户名:').strip()
            password = input('请输入密码:').strip()
            re_password = input('请确认密码:').strip()
            if password == re_password:
                send_dic = {'username': username,
                            'password': password,
                            'type': 'register',
                            'user_type': 'admin'}
                # {'flag': False, 'msg': '用户已存在!'}
                # {'flag': True, 'msg': '注册成功'}
                back_dic = common.send_msg_back_dic(send_dic, client)
    
                if back_dic.get('flag'):
                    print(back_dic.get('msg'))
                    break
    
                else:
                    print(back_dic.get('msg'))
    
    def login(client):
        while True:
            username = input('请输入用户名: ').strip()
            password = input('请输入密码:').strip()
    
            send_dic = {
                'type': 'login',  # 判断对应的接口
                'username': username,
                'password': password,
                'user_type': 'admin'
            }
            # {'flag': False, 'msg': '用户不存在'}
            back_dic = common.send_msg_back_dic(send_dic, client)
    
            if back_dic.get('flag'):
                session = back_dic.get('session')
                user_info['cookies'] = session
                print(back_dic.get('msg'))
                break
    
            else:
                print(back_dic.get('msg'))
    
    # 上传电影
    def upload_movie(client):
        while True:
            # 1.打印电影列表
            movie_list = common.get_movie_list()
            for index, movie in enumerate(movie_list):
                print(index, movie)
    
            choice = input('请输入上传的电影编号:').strip()
    
            if not choice.isdigit():
                print('请输入数字!')
                continue
    
            choice = int(choice)
    
            if choice not in range(len(movie_list)):
                print("请选择正确编号!")
                continue
    
            # 用户选择电影
            movie_name = movie_list[choice]
    
            # 上传电影绝对路径
            movie_path = os.path.join(
                settings.UPLOAD_FILES, movie_name
            )
    
            # 2.去服务端校验电影是否存在
            file_md5 = common.get_movie_md5(movie_path)
    
            send_dic = {
                'type': 'check_movie',
                'session': user_info.get('cookies'),
                'file_md5': file_md5
            }
    
            back_dic = common.send_msg_back_dic(
                send_dic, client)
    
            if back_dic.get('flag'):
                # 电影可以上传
                print(back_dic.get('msg'))
    
                # 上传电影功能字典
                send_dic = {
                    'type': 'upload_movie',
                    'file_md5': file_md5,
                    # 大小用来判断服务端需要接受文件的大小
                    'file_size': os.path.getsize(movie_path),
                    'movie_name': movie_name,
                    'session': user_info.get('cookies')
                }
    
                is_free = input('上传电影是否免费: y/n').strip()
    
                if is_free == 'y':
                    send_dic['is_free'] = 1
    
                else:
                    send_dic['is_free'] = 0
    
                back_dic = common.send_msg_back_dic(
                    send_dic, client, file=movie_path)
    
                if back_dic.get('flag'):
                    print(back_dic.get('msg'))
                    break
    
            else:
                print(back_dic.get('msg'))
    
    
    
        #
        #
        # send_dic = {'type': 'upload_movie','session': user_info.get('cookies')}
        # back_dic = common.send_msg_back_dic(send_dic, client)
        # print(back_dic)
    
    # 删除电影
    def delete_movie(client):
        while True:
            # 1.从服务端获取电影列表
            send_dic = {'type': 'get_movie_list',
                        'session': user_info.get('cookies')}
    
            # 发送获取电影请求
            back_dic = common.send_msg_back_dic(
                send_dic, client)
    
            if back_dic.get('flag'):
                back_movie_list = back_dic.get('back_movie_list')
                # 打印选择的电影
                for index, movie_list in enumerate(back_movie_list):
                    print(index, movie_list)
    
                # 2.选择需要删除的电影
                choice = input('请输入需要删除的电影编号:').strip()
    
                if not choice.isdigit():
                    continue
    
                choice = int(choice)
    
                if choice not in range(len(back_movie_list)):
                    continue
    
                # 获取电影ID,传递给服务端,让服务端去mysql数据库修改当前电影对象的is_delete=1
                movie_id = back_movie_list[choice][2]
    
                send_dic = {
                    'type': 'delete_movie', 'movie_id': movie_id,
                    'session': user_info.get('cookies')
                }
    
                # 发送删除电影请求
                back_dic = common.send_msg_back_dic(send_dic, client)
    
                if back_dic.get('flag'):
                    print(back_dic.get('msg'))
                    break
            else:
                print(back_dic.get('msg'))
                break
    
    # 发布公告
    def put_notice(client):
        title = input('请输入公告标题:').strip()
        content = input('请输入公告内容:').strip()
    
        send_dic = {
            'type': 'put_notice',
            'session': user_info.get('cookies'),
            'title': title,
            'content': content
        }
        back_dic = common.send_msg_back_dic(send_dic, client)
    
        print(back_dic.get('msg'))
    
    func_dic = {
        '1': register,
        '2': login,
        '3': upload_movie,
        '4': delete_movie,
        '5': put_notice,
    }
    
    def admin_view():
    
        sk_client = socket_client.SocketClient()
        client = sk_client.get_client()
    
        while True:
            print('''
                1.注册
                2.登录
                3.上传视频
                4.删除视频
                5.发布公告
                q.退出
            ''')
    
            choice = input('请选择功能编号:').strip()
    
            if choice == 'q':
                break
    
            if choice not in func_dic:
                continue
    
            func_dic.get(choice)(client)
    admin.py
    from core import admin, user
    
    
    func_dic = {
    
        '1': admin.admin_view,
        '2': user.user_view,
    }
    def run():
        while True:
            print('''
            1.管理员功能
            2.用户功能
            q.退出
            ''')
    
            choice = input('请选择功能编号: ').strip()
    
            if choice == 'q':
                break
    
            if choice not in func_dic:
                continue
    
            func_dic.get(choice)()
    src.py
    from tcp_client.socket_client import SocketClient
    from lib import common
    from conf import settings
    import time
    import os
    user_info = {
        'cookies': None,
        'is_vip': None
    }
    
    def register(client):
    
        while True:
            username = input('请输入用户名:').strip()
            password = input('请输入密码:').strip()
            re_password = input('请确认密码:').strip()
            if password == re_password:
                send_dic = {'username': username,
                            'password': password,
                            'type': 'register',
                            'user_type': 'user'}
                # {'flag': False, 'msg': '用户已存在!'}
                # {'flag': True, 'msg': '注册成功'}
                back_dic = common.send_msg_back_dic(send_dic, client)
    
                if back_dic.get('flag'):
                    print(back_dic.get('msg'))
                    break
    
                else:
                    print(back_dic.get('msg'))
    
    def login(client):
        while True:
            username = input('请输入用户名: ').strip()
            password = input('请输入密码:').strip()
    
            send_dic = {
                'type': 'login',  # 判断对应的接口
                'username': username,
                'password': password,
                'user_type': 'user'
            }
            # {'flag': False, 'msg': '用户不存在'}
            back_dic = common.send_msg_back_dic(send_dic, client)
    
            if back_dic.get('flag'):
                session = back_dic.get('session')
                user_info['cookies'] = session
                user_info['is_vip'] = back_dic.get('is_vip')
                print(back_dic.get('msg'))
    
                # 打印最新公告
                if back_dic.get('new_notice'):
                    print(back_dic.get('new_notice'))
    
                break
    
            else:
                print(back_dic.get('msg'))
    
    # 购买会员功能
    def buy_vip(client):
        if user_info.get('is_vip'):
            print('已经是会员了!')
            return
    
        is_vip = input('购买会员(y or n)?').strip()
        if is_vip == 'y':
            send_dic = {
                'type': 'buy_vip',
                'session': user_info.get('cookies')
            }
    
            back_dic = common.send_msg_back_dic(
                send_dic, client)
    
            if back_dic.get('flag'):
                print(back_dic.get('msg'))
    
    
    
        else:
            print('*穷*,快去打工赚钱!')
    
    # 查看所有电影
    def check_all_movie(client):
        send_dic = {
            'type': 'get_movie_list',
            'session': user_info.get('cookies')
        }
    
        back_dic = common.send_msg_back_dic(
            send_dic, client)
        if back_dic.get('flag'):
            print(back_dic.get('back_movie_list'))
        else:
            print(back_dic.get('msg'))
    
    # 下载免费电影
    def download_free_movie(client):
        while True:
            # 1.获取服务端所有免费电影
            send_dic = {
                'type': 'get_movie_list',
                'session': user_info.get('cookies'),
                'movie_type': 'free'
            }
            back_dic = common.send_msg_back_dic(send_dic, client)
            if back_dic.get('flag'):
                # 2.选择下载的免费电影,并提交给服务端
                movie_list = back_dic.get('back_movie_list')
    
                for index, movie in enumerate(movie_list):
                    print(index, movie)
    
                choice = input('请输入下载电影编号:').strip()
    
                if not choice.isdigit():
                    continue
    
                choice = int(choice)
    
                if choice not in range(len(movie_list)):
                    continue
    
                movie_name, movie_type, movie_id = movie_list[choice]
    
                send_dic = {'type': 'download_movie',
                            'session': user_info.get('cookies'),
                            'movie_id': movie_id,
                            'movie_name': movie_name,
                            'movie_type': movie_type}
    
                back_dic = common.send_msg_back_dic(send_dic, client)
    
                if back_dic.get('flag'):
                    # 3.开始下载电影
                    movie_path = os.path.join(settings.DOWNLOAD_FILES, movie_name)
                    movie_size = back_dic.get('movie_size')
    
                    # 准备下载电影: 判断是否是VIP,若不是则等待广告播放
                    wait_time = back_dic.get('wait_time')
    
                    if wait_time:
                        print('惠州某工厂上线啦....')
                        time.sleep(wait_time)
    
                    recv_data = 0
                    with open(movie_path, 'wb') as f:
                        while recv_data < movie_size:
                            data = client.recv(1024)
                            f.write(data)
                            recv_data += len(data)
                        f.flush()
    
                    print('免费电影下载成功!')
                    break
    
            else:
                print(back_dic.get('msg'))
                break
    
    
    # 下载收费电影
    def download_pay_movie(client):
        while True:
    
            if user_info.get('is_vip'):
                is_pay = input('VIP打骨折,收费5$一部(y or n):').strip()
            else:
                is_pay = input('普通用户,收费50$一部(y or n):').strip()
    
            if not is_pay == 'y':
                print('Gun去充钱!')
                break
    
            # 1.获取服务端所有免费电影
            send_dic = {
                'type': 'get_movie_list',
                'session': user_info.get('cookies'),
                'movie_type': 'pay'
            }
            back_dic = common.send_msg_back_dic(send_dic, client)
            if back_dic.get('flag'):
                # 2.选择下载的免费电影,并提交给服务端
                movie_list = back_dic.get('back_movie_list')
    
                for index, movie in enumerate(movie_list):
                    print(index, movie)
    
                choice = input('请输入下载电影编号:').strip()
    
                if not choice.isdigit():
                    continue
    
                choice = int(choice)
    
                if choice not in range(len(movie_list)):
                    continue
    
                movie_name, movie_type, movie_id = movie_list[choice]
    
                send_dic = {'type': 'download_movie',
                            'session': user_info.get('cookies'),
                            'movie_id': movie_id,
                            'movie_name': movie_name,
                            'movie_type': movie_type}
    
                back_dic = common.send_msg_back_dic(send_dic, client)
    
                if back_dic.get('flag'):
                    # 3.开始下载电影
                    movie_path = os.path.join(settings.DOWNLOAD_FILES, movie_name)
                    movie_size = back_dic.get('movie_size')
    
                    # 准备下载电影: 判断是否是VIP,若不是则等待广告播放
                    wait_time = back_dic.get('wait_time')
    
                    if wait_time:
                        time.sleep(wait_time)
    
                    recv_data = 0
                    with open(movie_path, 'wb') as f:
                        while recv_data < movie_size:
                            data = client.recv(1024)
                            f.write(data)
                            recv_data += len(data)
                        f.flush()
    
                    print('收费电影下载成功!')
                    break
    
            else:
                print(back_dic.get('msg'))
                break
    
    # 查看下载记录功能
    def check_download_record(client):
        send_dic = {'type': 'check_download_record',
                    'session': user_info.get('cookies')}
    
        back_dic = common.send_msg_back_dic(send_dic, client)
    
        if back_dic.get('flag'):
            # 返回电影下载记录
            print(back_dic.get('record_list'))
    
        else:
            print(back_dic.get('msg'))
    
    # 查看所有公告
    def check_all_notice(client):
        send_dic = {'type': 'check_all_notice',
                    'session': user_info.get('cookies')}
        back_dic = common.send_msg_back_dic(send_dic, client)
        if back_dic.get('flag'):
            print(back_dic.get('back_notice_list'))
        else:
            print(back_dic.get('msg'))
    
    func_dic = {
        '1': register,
        '2': login,
        '3': buy_vip,
        '4': check_all_movie,
        '5': download_free_movie,
        '6': download_pay_movie,
        '7': check_download_record,
        '8': check_all_notice,
    }
    
    def user_view():
        sk_client = SocketClient()
        client = sk_client.get_client()
        while True:
            print('''
            1.注册
            2.登录
            3.充会员
            4.查看视频
            5.下载免费视频
            6.下载会员视频
            7.查看观影记录
            8.查看所有公告
            ''')
    
            choice = input('请选择功能编号:').strip()
    
            if choice == 'q':
                break
    
            if choice not in func_dic:
                continue
    
            func_dic.get(choice)(client)
    user.py

    download_files

    下载文件文本

    lib

    import json
    import struct
    from conf import settings
    import os
    import hashlib
    
    def send_msg_back_dic(send_dic, client, file=None):
        data_bytes = json.dumps(send_dic).encode('utf-8')
        headers = struct.pack('i', len(data_bytes))
        client.send(headers)
        client.send(data_bytes)
    
        # 上传电影
        if file:
            with open(file, 'rb') as f:
                for line in f:
                    # print(line)
                    client.send(line)
    
        headers = client.recv(4)
        data_len = struct.unpack('i', headers)[0]
        data_bytes = client.recv(data_len)
        back_dic = json.loads(data_bytes.decode('utf-8'))
        return back_dic
    
    
    def get_movie_list():
        if os.path.exists(settings.UPLOAD_FILES):
            movie_list = os.listdir(settings.UPLOAD_FILES)
            if movie_list:
                return movie_list
    
    # 获取电影的md5值
    def get_movie_md5(movie_path):
    
        md5 = hashlib.md5()
        # 截取电影的4个位置的md5值
        movie_size = os.path.getsize(movie_path)
    
        # 从电影的4个位置个截取10个bytes数据
        current_index = [
            0, movie_size // 3, (movie_size // 3) * 2,
            movie_size - 10
        ]
    
        with open(movie_path, 'rb') as f:
    
            for index in current_index:
    
                f.seek(index)
                data = f.read(10)
                md5.update(data)
    
        return md5.hexdigest()
    common.py

    tcp_client

    import socket
    
    
    class SocketClient:
        def __init__(self):
            self.client = socket.socket()
            self.client.connect(
                ('127.0.0.1', 9527)
            )
    
        def get_client(self):
            return self.client
    
    # sk = SocketClient()
    # client = sk.get_client()
    socket_client

    upload_files

    上传文件文本

    readme

    start.py

    import os
    import sys
    from core import src
    
    sys.path.append(
        os.path.dirname(__file__)
    )
    
    
    if __name__ == '__main__':
        src.run()
    start.py
  • 相关阅读:
    html5中利用FileReader来读取文件。
    在响应式布局中,碰到图片不会自动缩放,因此需要一段js脚本
    简单的游戏副本刷新倒计时制作
    在webpack4 中利用Babel 7取消严格模式方法
    vue中按需引入mint-UI报Error: .plugins[3][1] must be an object, false, or undefined
    如何在webpack开发中利用vue框架使用ES6中提供的新语法
    Module not found: Error: Can't resolve '@babel/runtime/helpers/classCallCheck' and Module not found: Error: Can't resolve '@babel/runtime/helpers/defineProperty'
    DOTNET CORE源码分析之IOC容器结果获取内容补充
    DOTNET CORE源码分析之IServiceProvider、ServiceProvider、IServiceProviderEngine、ServiceProviderEngine和ServiceProviderEngineScope
    DOTNET CORE源码分析之IServiceCollection、ServiceCollection和ServiceCollectionDescriptorExtensions
  • 原文地址:https://www.cnblogs.com/qinsungui921112/p/11576340.html
Copyright © 2020-2023  润新知