网络项目OJ 在线判题系统

点我查看代码

思维导图 ,一看立马懂

在这里插入图片描述

思维导图大纲:

1 获取题目列表
1 获取题目列表
访问服务器特定的ip + port
2 渲染展示all_questions的html页面
1 设置html页面标题
2 设置每个题目超链接
3 建立数据字典 + 和C++正则表达式配合使用,匹配展示每个题目的id + name + star
4 设置form表单
1 设置答题的代码编辑框textarea
2 设置提交按钮submit
3 设置提form表单的执行动作----->向服务器该题目的目录提交 提交方式选用post较安全

2 选择题目
1 获取该题目的describe + header
实现:html超链接
2 渲染展示该题目的html页面
数据字典片段 + c++ 正则表达式

3 作答并提交
1 服务器对用户作答数据进行捕捉并保存
1 抓取并解析数据包 name=xxx&body=xxx
2 拆分数据包 得到name和 body
3 获取题目id 和 code
2 由题目Id 查找该题目在服务端保存的main函数
3 将main函数和用户提交代码进行拼接

4 服务器响应运行结果
1 将拼接完成的代码交给编译器Compiler
2 编译器对拼接完整的代码进行分析
1 检查请求是否有效–>req[“code”].empty()
2 将拼接后的代码保存在文件中 ,防止多用户做题,文件统一命名 tmp_ + 时间戳
3 准备编译
1 构造编译命令
2 fork创建新进程
1 父进程回收资源
2 子进程准备编译条件
1 准备捕捉编译错误的信息,保存在文件中
2 正式程序替换,执行构造好的编译命令
3 防止程序替换失败,及时退出exit
3 验证是否产生了可执行程序–>stat()
4 运行
fork 新进程
1 父进程回收资源
2 子进程准备运行条件
1 准备接收stdout/stderr的文件,将stdout/stderr 重定向到准备好的文件中
2 设置时间限制alarm + 内存限制setrlimit
3 进程程序替换,去运行编译生成的可执行程序
4 防止程序替换失败,及时退出exit
5 响应
1 接收运行进程退出的信号
1 正常退出errorno -->ok reason -->ok
2 异常退出errorno–> 错误码 reason–> signal
3 运行信息html页面的渲染
数据字典
6 清理服务端垃圾文件
unlink(filename)

1 环境准备:

httplib.h开源库

2 使用C++11特性 需要版本
gcc -v。 查看 版本 4.8.2之后的版本支持
版本升级指令: source /opt/rh/devtoolset-4/enable

yum -y install jsoncpp-devel

需求分析:

1 在浏览器中展示题目    		 oj_server 试题模块
2 用户可以选择题目进行作答		 oj_server 试题模块
3 提交代码到后台	
4 针对用户代码进行编译,
5 后台运行代码			
6 将运行结果进行打包
7 把结果返回给客户端。		  oj_server

模块划分:

1 oj_server模块
1 提供http服务,需要下面四个模块的支持
1.1 获取题目列表
1.2 提交选中题目的
1.3 提交题目描述,和题目代码,代码的编辑框

2 试题模块
2.1 从本地加载题目
配置文件的格式;规定统一
题目 id、path、name、难易度
eg:回文数 ./oj_data/1 简单
2.2 加载题目的配置文件,使用数据结构/unordered_map保存加载出来的题目介绍信息,最重要的是路径
2.3 针对具体的某一道题目而言,需要根据路径进行加载
1 desc.txt描述信息
2 header.cpp存放本题目的头文件和实现类
3 tail.cpp 存放main函数以及所有的测试用例
2.4 提供获取所有题目的接口
2.5 提供获取单个题目的接口

3 编译运行模块
将用户提交的code写到文件中,并编译源码文件
1 构造编译命令
2 编译
3 检查是否生成可执行程序
4 运行(folk子进程执行,为防止多题目同时运行,引起后台显示分不清,将运行信息重定向到自己特定文件中)
5 构造响应给用户的信息(errono、reason、)
6 及时清理掉配置文件 (unlink)
4 日志模块
1 显示错误类型
2 以文件的形式保存执行期间得日志文件,日志文件统一命名为 tmp + 时间戳格式,防止多用户同时作答。

5 工具模块
1 切割类: 切割字符串,得到想要的信息 题目id 和 stdin
2 解码类: 对网页Json数据包进行解码,拿到代码,准备保存
3 文件操作类;
1 写文件,将数据写入到文件中保存,即将所有代码拼接完整保存起来
2 读文件, 从文件中拿出数据使用, 即拿出完整代码准备执行

static Template* GetTimeplate  (路径, 渲染方式)
1 DO_NOT_STRIP. 逐字逐句渲染到html模版文件中
2 STRIP_BLANK_LINES。删除空行渲染到html模版文件中
3 STRIP_WITHESPACE. 删除空行和每一行的首尾空格渲染到html模版文件中

1 数据字典: —>需要填充的数据
2 获取了需要填充的html文件
3 渲染

底层存储试题的数据结构的选择
Map——>底层红黑树,查询效率(logN)
unordered_map. 查询效率高 O(1)。查询性能更佳。 因此选择unordered_map

遇到 问题:题目存储 刚开始每个题目信息占多行,由于其中某个题目信息出问题了,导致后续题目都无法正常读取,

解决方案:每个题目信息占一行

拉去题目 使用C++中的文件流fstream来加载文件
iostream。处理的是控制台IO
fstream。 处理命名文件的IO
stringstream。处理内存中string对象的IO
ifstream/ofstream。 从文件中读/向文件中写

ifstram(const char* filename, ios_base::openmode = ios_base::in)以读方式打开
i以读方式打开
o以写方式打开

使用boost库中split函数进行对题目字符串切割。

	**#inlude <boost/algorithm/string.hpp>**
	boost::split(存储位置,切割对象, 切割标记,以字符还是字符串的方式切割);
	切割标记 boost::is_any_of(标记 )
	以字符切割标记boost::token_compress_on
	切割成字符串: boost::token_compress_off

使用模版技术展示Html页面

几个标签:
head :描述了html的各种标签
title:标题栏
meta: 标记了各种源数据,可以背浏览器识别, key -value。meta<Content-Type, content = “text/html; charset=UTF-8”>.meta标签可以只定义一个
body: 页面主体

标签 :可以换行, 在html页面中定义一个分区 a标签: 定义超链接 a + href: 告诉 浏览器具体链接哪个地址 Form 标签: 浏览器监测到form时, 当前页面就可以给服务器提交数据 用户写完数据之后提交 action:向哪个服务器提交 method 用什么方法提交 **enctype 提交数据的格式===>json** 代码编辑框(textarea 可以定义名称、行、列数、内容<>/text/area)包含一些标签:
  名称 name="xx"
  行   rows=“xx”
  列   cols=“xx”
提交标签:
〈input〉
	数据类型(提交submit)数据值:展示在页面
	formenctype(回复盖前面的数据格式)

google提供 ctemplate:

可以使逻辑和界面分离,后台负责计算,在使用模版技术将计算后的值填充到预定义的html页面中

两个部分:
1 模版:界面的展示形式
2 数据字典:填充模版的数据

四种标记:
1 变量: {{变量名}}
2 片段: {{#片段名}}
3 包含: {{>模版名称}} 一个模版中包含另一个模版 很少使用
4 注释: {{!}}
链接https://gitee.com/HGtz2222/ThirdPartLibForCpp/tree/master/1
实现日志模块

保存日志的时间。,行号。,文件 日志等级等信息

对时间获取和时间格式转换函数进行查询

渲染三方面:

 1 渲染展示所有题目页面
 2 渲染展示题目内容一面 
 3 渲染原因页面(错误?正确?)

explict:显示声明。implict隐士声明

C++ 提供正则表达式这样的类

可以将string 分成多个string, 通过match[]可以获取每个片段
正则表达式来匹配题目
\b单词的分界
* 匹配任意长度字符串
\d 匹配一个个位数 \d+可以匹配高位数
\在C++中为转义字符,因此需要源码转义 R"()"
(\d+) 分组应用

《题目页面 》

1。题目信息。
2。题目编辑框

JsonCpp主要提供三个类

json底层还是通过键值对来实现的
主要应下面三个类
Value
Reader
Writer

Json命名空间
Json::Value

Req 每条数据用&相连接 ,name=xxx&stdin=xxx
stdin 是form表单 ,name是题目

POST 响应阶段

1。获取关键信息—〉代码
2。编译&运行
3 将执行结果发送给浏览器

头文件 #include <sys/resource.h>
struct rlimit rlt ;设置内存 alram(设置时间)
rlt.rlimit_cur //内存下线
rlt.rlimit_max// 内存上线。
RLIM_INFINITY. 无上限

setrlimit(RLIMIT_AS, &rlt); 令设置生效

遇到的问题

**遇到问题 1:**在构建渲染单个题目模版时一直不成功, 最后发现是因为多写了一个数据字典的片段(让我迷惑半天)

**遇到问题 2:**一直过不了。显示原因是被9号信号强制退出 在我思来想去之后发现 ,原来是内存设置太小了, 将内存限制改掉之后,结果正常

遇到问题 3: 版本无缘无故自己降级。导致不能运行 ; 将这条指令 source /opt/rh/devtoolset-4/enable 加到.bashrc最后一行。 再source ~/.bashrc

遇到问题 4 : 模版库找不到链接库 : 解决方案:第一步。添加环境变量, 第二步。makefile 添加 -l模版库的所在路径

遇到问题5 :题目存储 刚开始每个题目信息占多行,由于其中某个题目信息出问题了,导致后续题目都无法正常读取,

发布了107 篇原创文章 · 获赞 44 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44030580/article/details/105411750