python-优酷系统管理员视图粗糙版(无详细注释)
Tank-YouKu(仅管理员功能粗糙版)
优酷系统管理员视图功能
- 注册
- 登录
- 上传视频
- 删除视频
- 发布公告
前期准备
先创建好数据库以及各数据表
安装 pymysql 模块 、安装 DBUtils 模块
配置好服务端的 db_pool 中的数据库信息
创库创表语句
手动创建数据库 youku_demo
, 需配置数据库编码 utf8
(安装时配置好了命令行中就不用管)
创建数据库:create database youku_demo;
选择该数据库:use youku_demo
,然后执行下面的一堆sql代码,或者手动导入
创表代码及测试数据
测试用户:tank
密码: 123
/*
Navicat MySQL Data Transfer
Source Server : localhost-E
Source Server Type : MySQL
Source Server Version : 50645
Source Host : localhost:3306
Source Schema : youku_demo
Target Server Type : MySQL
Target Server Version : 50645
File Encoding : 65001
Date: 28/08/2019 21:22:47
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for download_record
-- ----------------------------
DROP TABLE IF EXISTS `download_record`;
CREATE TABLE `download_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NULL DEFAULT NULL,
`movie_id` int(11) NULL DEFAULT NULL,
`download_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Table structure for movie
-- ----------------------------
DROP TABLE IF EXISTS `movie`;
CREATE TABLE `movie` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`is_free` int(11) NULL DEFAULT NULL,
`file_md5` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_id` int(11) NULL DEFAULT NULL,
`is_delete` int(11) NULL DEFAULT NULL,
`upload_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Table structure for notice
-- ----------------------------
DROP TABLE IF EXISTS `notice`;
CREATE TABLE `notice` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_id` int(11) NULL DEFAULT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of notice
-- ----------------------------
INSERT INTO `notice` VALUES (1, \'test1\', \'测试发布公告是否正常\', 1, \'2019-08-28 21:18:38\');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`is_vip` int(11) NULL DEFAULT NULL,
`is_locked` int(11) NULL DEFAULT NULL,
`user_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`register_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, \'tank\', \'e23087636dfcd7addf39e32f89e25d44\', 0, 0, \'admin\', \'2019-08-28 21:18:10\');
SET FOREIGN_KEY_CHECKS = 1;
数据库结构
安装pymysql模块
参见博客: MySQL-注释-Navicat基本使用-复杂查询练习题-解题思路-pymysql操作数据库-SQL注入-05 的安装部分
安装DBUtils模块
在命令行输入pip3 install DBUtils
开始安装
配置 db_pool
根据自己电脑的mysql 情况配置
项目架构与数据流向
目录结构
server目录结构
client目录结构
服务端代码
start.py
import os
import sys
from tcp_server.socket_server import SocketServer
sys.path.append(os.path.dirname(__file__))
if __name__ == \'__main__\':
server = SocketServer()
server.run()
tcp_server/socket_server.py
import socket
import struct
import json
from interface import common_interface
from interface import admin_interface
from concurrent.futures import ThreadPoolExecutor
from threading import Lock
from lib import lock_file
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
}
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()
self.pool.submit(self.working, conn, addr)
# 任务分发
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 = client_back_dic.get(\'type\')
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\'))
client_back_dic[\'addr\'] = str(addr)
self.dispatcher(client_back_dic, conn)
except Exception as e:
print(e)
conn.close()
break
interface/common_interface.py
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):
username = client_back_dic.get(\'username\')
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()
user_data.user_online[addr] = [session, user_obj.id]
lock_file.mutex.release()
send_dic = {\'flag\': True, \'msg\': \'登录成功!\', \'session\': session}
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:
back_movie_list.append(
# [电影名称、是否免费、电影ID]
[movie_obj.name, \'免费\' if movie_obj.is_free else "收费", 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)
db/models.py
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\')
orm/orm.py
\'\'\'
定义字段类
\'\'\'
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)
orm/mysql_control.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)
orm/db_pool.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=\'000000\',
database=\'youku_demo\',
charset=\'utf8\',
autocommit=\'True\'
)
lib/common.py
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):
data_bytes = json.dumps(send_dic).encode(\'utf-8\')
headers = struct.pack(\'i\', len(data_bytes))
conn.send(headers)
conn.send(data_bytes)
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]
user_session = user_data.user_online.get(addr)
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
# if __name__ == \'__main__\':
#
# # print(get_time())
# print(get_random_code())
# 05248e1b1a10ac08872f8dd5d9dbd814
# 161df6d362dc52b0037d938a0717963e
# aabd3987f88b2db46566cf6d9ec864e2
lib/lock_file.py
mutex = None
db/user_data.py
user_online = {
# addr: [session, user_id]
}
interface/admin_interface.py
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:
print(1111)
send_dic = {
\'flag\': False,
\'msg\': \'电影已存在!\'
}
else:
print(222)
send_dic = {
\'flag\': True,
\'msg\': \'电影可以上传\'
}
common.send_data(send_dic, conn)
def delete_movie_interface(client_back_dic, conn):
# 直接删除
movie_obj = models.Movie.select(id=client_back_dic.get(\'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)
conf/settings.py
import os
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
DOWNLOAD_PATH = os.path.join(BASE_PATH, \'download_files\')
客户端代码
start.py
import os
import sys
from core import src
sys.path.append(os.path.dirname(__file__))
if __name__ == \'__main__\':
src.run()
core/src.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)()
core/admin.py
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\'
}
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
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)
tcp_client/socket_client.py
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
lib/common.py
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()
conf/settings.py
import os
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
UPLOAD_FILES = os.path.join(BASE_PATH, \'upload_files\')