涵盖内容:
线程池,锁机制,session验证机制,简易版orm,大文件md5校验,数据库操作
服务端目录
conf
import os BASE_PATH = os.path.dirname( os.path.dirname(__file__) ) DOWNLOAD_PATH = os.path.join( BASE_PATH, 'download_files')
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')
user_online = { # addr: [session, user_id] }
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)
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
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)
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
mutex = None
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()
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)
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' )
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
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() #
客户端目录
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')
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)
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)()
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)
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()
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()
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()