卫生室可以做网站吗,上海seo排名,深圳手机网站开发,郑州电商运营培训C项目 – 负载均衡OJ#xff08;三#xff09;online_judge 文章目录 C项目 -- 负载均衡OJ#xff08;三#xff09;online_judge一、基于MVC结构的oj服务设计1.结构与功能 二、oj_model.hpp1.建立文件版题库2.文件版题库的服务模块3. MySQL版题库3.1.创建名为oj_client的用…C项目 – 负载均衡OJ三online_judge 文章目录 C项目 -- 负载均衡OJ三online_judge一、基于MVC结构的oj服务设计1.结构与功能 二、oj_model.hpp1.建立文件版题库2.文件版题库的服务模块3. MySQL版题库3.1.创建名为oj_client的用户创建数据库oj并给oj_client赋权3.2. 设计表结构3.3.引入MySQL链接库3.4.在oj_model中访问连接数据库 三、oj_view.hpp1.安装与测试ctemplate库2.view模块编写 四、oj_control.hpp1.负载均衡模块2.Control模块 五、oj_server.cc1.Makefile2.设置用户请求的服务路由功能3.构建正式的OJ功能4.形成正式的oj_server5.前端界面6.测试 六、编写顶层makefile 一、基于MVC结构的oj服务设计
1.结构与功能
该模块功能
获取首页用题目列表充当编辑区域页面提交判题功能(编译并运行)
MVC结构
M: Model,通常是和数据交互的模块比如对题库进行增删改查文件版MySQLV: view, 通常是拿到数据之后要进行构建网页渲染网页内容展示给用户的(浏览器)C: control, 控制器就是我们的核心业务逻辑
二、oj_model.hpp
这是和数据交互的模块对外提供访问数据的接口
1.建立文件版题库
题目的信息包括
题目的编号题目的标题题目的难度题目的描述题面时间要求(内部处理)空间要求(内部处理)
两批文件构成
questions.list : 题目列表不需要题目的内容 所有的题目都存放在questions路径下 题目的描述(desc.txt)题目的预设置代码(header.cpp), 测试用例代码(tail.cpp) 测试用例tail.cpp 为了在实际编译的时候文件中没有#include “header.hpp”需要在编译服务调用g的时候后面加上一个编译选项-D COMPILER_ONLINE:
这两个内容是通过题目的编号产生关联的
2.文件版题库的服务模块
文件版model模块
当用户提交代码后OJ是将用户写好的header.cpp拼接上题号对应的测试用例tail.cpp形成新的源代码并发送到compile_and_run模块运行运行结果返回给用户测试用例中的条件编译不想让编译器编译的时候保留它而是裁剪掉g -D COMPILER_ONLINE根据题目list文件加载所有的题目信息道内存中题目的所有信息由一个结构体类型存储Model类中使用哈希表保存题号与题目信息的映射 LoadQuestionList函数用于加载所有的题目信息道内存中以哈希表的形式GetAllQuestions用于获取所有的题目信息GetOneQuestion用于获取指定题目信息
3. MySQL版题库
3.1.创建名为oj_client的用户创建数据库oj并给oj_client赋权
mysql use mysql
mysql create user oj_client% identified by password;
mysql create database oj;
mysql grant all on oj.* to oj_client%;登录oj_client用户可以看到oj数据库
3.2. 设计表结构
使用MySQLWorkbench来进行图形化界面建表 创建与服务器MySQL的连接 连接上在oj数据库创建oj_questions表
create table if not exists oj_questions (number int primary key auto_increment comment 题目的编号,title varchar(128) not null comment 题目的标题,star varchar(8) not null comment 题目的难度,desc text not null comment 题目的描述,header text not null comment 题目预设给用户的代码,tail text not null comment 题目的测试用例代码,cpu_limit int default 1 comment 题目的cpu运行时间限制,mem_limit int default 50000 comment 题目的内存空间限制
)engineInnoDB default charsetutf8;在Workbench中录题 如果想只执行这一条语句就选中然后执行 点击form editer开始录入 录制完成后点apply 录制成功
3.3.引入MySQL链接库
MySQL版model模块
如果系统中本身就有MySQL连接的库就不需要再引入了 如果系统只有动态库文件没有devel开发库文件可以尝试用yum安装
yum install -y mysql-community-devel安装好devel(开发库)后我们只需要用 #include mysql/mysql.h 就可引入mysql库。 编译指令为
g -o oj_server oj_server.cc -stdc11 -L/usr/lib64/mysql/ -lmysqlclient如果系统中没有就需要自己安装 MySQL官网下载 导入服务器并解压 重命名 在oj_server目录下引入软链接 如果在运行时发现找不到MySQL的库 将库所在的路径写入该配置文件中这样运行时系统就知道去哪里寻找库了
3.4.在oj_model中访问连接数据库
oj_server是基于MVC实现的和数据打交道的只有oj_mode模块只需要更改该部分代码即可
QueryMySQL函数用于执行查询sql语句并将查询结果封装成Question插入到out中 关于MySQL Connector C中的接口作用见博客MySQL Connection C中的API介绍 GetAllQuestions用于向MySQL发出查询所有题目的指令GetOneQuestion用于向MySQL发出查询单个题目的指令
三、oj_view.hpp
这是构建网页的模块
1.安装与测试ctemplate库
ctemplate库的github仓库 这是谷歌开源的cpp网页渲染库 在ctemplate中数据是以字典的格式存放的 待渲染的网页中写入的是数据的key值渲染之后将key换成对应的value
测试网页渲染功能
html中待替换的key值需要使用{{key}} TemplateDictionary root是建立ctemplate参数目录结构相当于 unordered_mapstring, string test;root.SetValue向目录中添加你要替换的数据kv的相当于test.insert({ket, value});GetTemplate获取待渲染对象DO_NOT_STRIP是指保持html网页原貌tpl-Expand开始渲染替换字典中的kv返回新的网页结果到out_html
#include iostream
#include string
#include ctemplate/template.husing namespace std;int main()
{//html网页的地址string html ./test.html;string html_info lmx_xdu;//建立ctemplate参数目录结构//相当于 unordered_mapstring, string test;ctemplate::TemplateDictionary root(test); //向目录中添加你要替换的数据kv的//第一个参数是key第二个参数是value将html中的key全部替换为value//相当于test.insert({ket, value});root.SetValue(info, html_info);//获取待渲染对象//DO_NOT_STRIP是指保持html网页原貌ctemplate::Template *tpl ctemplate::Template::GetTemplate(html, ctemplate::DO_NOT_STRIP);//开始渲染替换字典中的kv返回新的网页结果到out_htmlstring out_html;tpl-Expand(out_html, root);cout 渲染的带参html是 endl;cout out_html endl;return 0;
}源html网页
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
body!--渲染参数,会被我们C代码中的数据替换, info就是上面SetValue(info, html_info)代码中的info会自动被std::string info_html中的内容替换--p{{info}}/pp{{info}}/pp{{info}}/pp{{info}}/p
/body
/html渲染后的html网页
2.view模块编写
view模块代码
View类用于网页的渲染
待渲染的网页模板在/template_html路径下
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title在线OJ题目列表/title
/head
bodytabletrth编号/thth标题/thth难度/th/tr{{#question_list}}trtd{{number}}/tdtda href/question/{{number}}{{title}}/a/tdtd{{star}}/td/tr{{/question_list}}/table
/body
/html!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title{{number}}.{{title}}/title
/head
bodyh4{{number}}.{{title}}.{{star}}/h4P{{desc}}/Ptextarea namecode cols100 rows50{{pre_code}}/textarea/body
/htmlAllExpandHtml函数将读取到的所有题目信息都渲染到网页上 在创建了root根目录后再向根目录中添加子目录用于替换question_list中的内容 可以将html中{{#question_list}}修饰的所有内容循环渲染 在题目的title处加上链接可以跳转到这道题的做题界面 OneExpandHtml用于单个题目信息的渲染
四、oj_control.hpp
这是业务的核心逻辑模块
1.负载均衡模块
负载均衡模块用于帮助Control选取负载最低的编译服务器所有编译服务器的配置信息都在以下文件中 Machine类用于保存每台编译服务器的具体信息一个编译服务对应一个Machine
包括ip、端口、负载以及每台服务器的锁由于mutex禁止拷贝因此使用指针
LoadBalance类用于实现负载均衡算法
类中保存所有服务器的类Machine记录所有上线和下线的主机并且有一把锁保证LoadBalance的数据安全LoadConf函数用于将配置文件中所有的服务器信息全部读取并保存SmartChoice函数用于根据所有上线服务器的负载信息选择负载最低的机器负载均衡的算法有1.随机数hash2.轮询hash 这里选取轮询hash通过遍历的方式,找到所有负载最小的机器OfflineMachine函数用于将指定的主机离线OnlineMachine函数用于上线所有已离线的主机是将所有_offline中的主机全部插入到_online中并删除_offline中的主机
2.Control模块
Control模块代码
Control类用于根据Model类中获取的题目数据来调用View类中的方法构建OJ网页
RecoveryMachine用于将所有的离线主机恢复为上线模式AllQuestions使用Model模块获取所有的题目信息再通过View模块将题目信息渲染到网页上Question根据指定题目构建网页Judge实现判题功能步骤如下 根据题目编号拿到对应的题目细节 in_json进行反序列化得到题目的id得到用户提交的源代码input输入参数 重新拼接用户代码测试用例代码形成新的代码 选择负载最低的主机规则一直选择直到主机可用否则就是全部挂掉 然后发起http请求得到结果 将结果赋值给out_jsonResult中定义了bool类型强转因此Result可以直接放在if语句里如果返回值存在就会返回true Post请求第一个参数是请求第二个参数是请求的参数第三个参数是请求的类型 cli.Post(/compile_and_run, compile_string, application/json;charsetutf-8)Post请求的返回值是Result对象 成员res_是Response的指针Result重载了-能够直接访问到Response Response中的成员有statue状态码其值等于200才证明这个http请求是成功的
五、oj_server.cc
1.Makefile
oj_server:oj_server.ccg -o $ $^ -stdc11 -L/usr/lib64/mysql/ -lpthread -ljsoncpp -lctemplate -lmysqlclient.PHONY:clean
clean:rm -f oj_server2.设置用户请求的服务路由功能
\d是正则表达式能够匹配到用户输入的所有数字; \d代表数字代表一个或多个; 正则匹配到的内容会存放在Request类中的matchs里面; question/100 -正则匹配R()原始字符串保持字符串内容的原貌不用做相关的转义设置首页为wwwroot在其中添加html网页vdcode中Tab可以生成网页骨架
#include iostream
#include ../Comm/httplib.h
#include ../Comm/util.hppusing namespace httplib;int main()
{//用户请求的服务路由功能Server svr;//获取所有题目列表svr.Get(/all_questions, [](const Request req, Response resp){resp.set_content(这是所有题目的列表, text/plain; charsetutf-8);}); //用户要根据题目编号获取题目的内容//question/100 -正则匹配//R()原始字符串保持字符串内容的原貌不用做相关的转义svr.Get(R(/question/(\d)), [](const Request req, Response resp){string number req.matches[1];resp.set_content(这是指定的一道题: number, text/plain; charsetutf-8);});//用户提交代码使用我们的判题功能1.每道题的测试用例 2.compile_and_runsvr.Get(R(/judge/(\d)), [](const Request req, Response resp){string number req.matches[1];resp.set_content(指定题目的判题: number, text/plain; charsetutf-8);});svr.set_base_dir(./wwwroot);svr.listen(0.0.0.0, 8080);return 0;
}首页 题目列表 指定题目 判题
3.构建正式的OJ功能
通过Control模块获取由所有题目信息构建的网页形成网页服务 set_content中的格式设置为html 通过Control模块获取单个题目信息构建的网页形成网页服务
首页 题目列表 做题界面
4.形成正式的oj_server
oj_server代码
添加Control对象实现加载题目和判题功能的请求
通过捕捉信号上线所有主机 通过捕捉ctrl \信号触发时调用Recovery重新上线所有主机
使用PostMan进行测试
创建三个compile_server服务端口号都是基于配置文件service_machine.conf中的 使用PostMan进行Post请求请求的文本形式为json代码内容为无法运行的初始代码返回的内容中有报错信息
5.前端界面
wwwroot首页 template_html界面
index.html
all_questions.html
one_question.html 这部分包含前后端交互
提交给Judge功能判题时需要的in_json内容主要有input和codesubmit函数用于获取页面上的题目信息形成请求url并通过ajax向后台发起基于http的json请求show_result函数用于得到结果解析并显示到 result中
6.测试
负载均衡测试 每次都会选择负载最低的机器运行
主机离线上线测试 所有主机离线后再次上线触发ctrl c信号就可以上线所有主机
六、编写顶层makefile
顶层makefile用于项目的编译、清理和发布
语句前面加是在运行时不显示这条语句项目的发布将生成的可执行程序和需要的库文件、网页文件等全部复制到output路径下
.PHONY: all
all :
#编译cd compiler_server;\make;\cd -;\cd online_judge;\make;\cd -;#项目发布
.PHONY : output
output :mkdir -p output/compiler_server;\mkdir -p output/online_judge;\cp -rf compiler_server/compile_server output/compiler_server;\cp -rf compiler_server/temp output/compiler_server;\cp -rf online_judge/conf output/online_judge;\cp -rf online_judge/questions output/online_judge;\cp -rf online_judge/template_html output/online_judge;\cp -rf online_judge/wwwroot output/online_judge;\cp -rf online_judge/oj_server output/online_judge;#项目清理
.PHONY : clean
clean :cd compiler_server;\make clean;\cd -;\cd online_judge;\make clean;\cd -;\rm -rf output;