ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

C++实现负载均衡在线OJ平台

2026/8/13 10:30:18 拓冰建站 浏览量
C++实现负载均衡在线OJ平台 在线OJ平台一、所用技术与开发环境二、项目宏观结构B/S架构三、编写思路四、编译Compile_server功能的设计五、编写运行功能六、编译Compile_run功能的设计七、把Compile_run功能打包成网络服务八、基于MVC结构的oj服务设计一、所用技术与开发环境所用技术C STL 标准库Boost准标准库(字符串切割)cpp-httplib 第三⽅开源⽹络库ctemplate 第三⽅开源前端⽹⻚渲染库jsoncpp 第三⽅开源序列化、反序列化库负载均衡设计多进程、多线程MySQL C connectAce前端在线编辑器(了解)html/css/js/jquery/ajax (了解)开发环境Ubuntu 20.04 云服务器vscodeMysql Workbench二、项目宏观结构B/S架构类似于力扣平台的题目列表在线编程三、编写思路1.Compile_server2.OJServer3.引入Mysql4.前端的页面设计四、编译Compile_server功能的设计提供的服务编译并运行代码得到格式化的结果编译代码服务需要让远端提交代码编译无非两种情况1.编译通过2.编译出错stderr — 需要形成临时文件已保存编译出错的结果如何编译fork() — 子进程进行g/gcc进行程序替换 —stderrstderr中的错误信息需要重定向展现给用户1编译功能Commpile_server/compiler.hpp - Compile方法(仅编译不拼接路径后缀) - fork子进程进行程序替换 - 其中引入了路径拼接和日志功能2路径拼接功能Comm/util.hpp - PathUtil::AddSuffix方法2日志功能Comm/log.hpp五、编写运行功能1.运行模块Run考虑代码跑完不需要考虑结果的正确与否并将结果重定向到不同文件当中 /************************************************* 程序运行: 1.代码跑完, 结果正确 2.代码跑完, 结果不正确 3.代码没有跑完, 异常 但是Run需要考虑代码跑完不需要考虑结果的正确与否 结果的正确与否: 由测试用例决定的! 当前模块只考虑: 是否正确运行完毕 ************************************************** 我们必须知道可执行程序是谁 一个程序在默认启动的时候 标准输入: 不处理 标准输出: 程序运行完成, 输出结果是什么 标准错误: 运行时错误信息 **************************************************/ 2.运行时时间空间的约束: 也就是时间复杂度空间复杂度, 防止恶意代码消耗CPU资源 setrlimit - AS CPU、struct rlimit 测试资源限制代码 #include iostream #include sys/time.h #include sys/resource.h #include unistd.h #include signal.h void handler(int signo) { std::cout signo: signo std::endl; } int main() { // 资源不足, 导致OS终止进程, 接收到信号终止的 --- 6号信号 for(int i 1; i 31; i) { signal(i, handler); } // 限制累计运行时长时间复杂度 // struct rlimit r; // r.rlim_cur 1; // r.rlim_max RLIM_INFINITY; // setrlimit(RLIMIT_CPU, r); // while(1); // 限制空间空间复杂度 struct rlimit r; r.rlim_cur 1024 * 1024 * 20; // 20M r.rlim_max RLIM_INFINITY; setrlimit(RLIMIT_AS, r); int count 0; while(true) { int *p new int[1024 * 1024]; count; std::cout size: count std::endl; sleep(1); } return 0; } 实际项目中限制CPU时长、内存大小 // 提供设置进程占用资源大小的接口 static void SetProcLimit(int _cpu_limit, int _mem_limit) { // 设置CPU时长 struct rlimit cpu_rlimit; cpu_rlimit.rlim_max RLIM_INFINITY; cpu_rlimit.rlim_cur _cpu_limit; setrlimit(RLIMIT_CPU, cpu_rlimit); // 设置内存大小 struct rlimit mem_rlimit; mem_rlimit.rlim_max RLIM_INFINITY; mem_rlimit.rlim_cur _mem_limit * 1024; setrlimit(RLIMIT_AS, mem_rlimit); }六、编译Compile_run功能的设计1.适配用户请求定制通信协议字段2.正确调用compile run方法3.形成唯一文件名补充认识jsoncpp安装jsoncpp: sudo apt install libjsoncpp-dev#include jsoncpp/json/json.h // 序列化工作 // 将结构化的数据转化成为一个字符串 // Value是一个Json的中间类, 可以填充kv值 Json::Value root; root[code] mycode; root[user] dyj; root[age] 21; // Json::StyledWriter writer; // 多行 Json::FastWriter writer; // 一行 std::string str writer.write(root); std::cout str std::endl;编译并运行compile_run.hpp七、把Compile_run功能打包成网络服务1.cpp-httplib 首先需要安装库 2.postman测试发起网络请求八、基于MVC结构的oj服务设计本质建立一个小型网站 1.获取首页、用题目列表充当 2.编辑区域页面 3.提交判题功能(编译并运行)MVCM - model通常是和数据交互的模块比如对题库进行增删查改之类的文件版、Mysql版V - view通常是拿到数据之后要进行构建网页渲染网页内容展示给用户的浏览器C - control控制器就是我们的核心业务逻辑1用户请求的服务路由功能// 用户请求的服务路由功能 Server svr; // 获取首页 svr.set_base_dir(./wwwroot); // 获取所有的题目列表 svr.Get(/all_questions,[](const Request req, Response resp){ resp.set_content(这是所有题目的列表, text/plain;charsetutf-8); }); // 用户要根据对应的题目编号, 获取题目的内容 // /questions/(\d) : (\d)是正则表达式, 数字匹配 // R() : 原始字符串raw string, 保证字符串内容的原貌, 不用做相关的转义 svr.Get(R(/question/(\d)), [](const Request req, Response resp){ std::string number req.matches[1]; resp.set_content(这是指定的一道题: number, text/plain;charsetutf-8); }); // 用户提交代码使用我们的判题功能1.每道题的测试用例 2.complie_and_run svr.Get(R(/judge/(\d)), [](const Request req, Response resp){ std::string number req.matches[1]; resp.set_content(指定题目的判题: number, text/plain;charsetutf-8); }); svr.listen(0.0.0.0, 8080);2建立文件版题库题目的编号、标题、难度、描述题面、时间要求(内部处理)、空间要求(内部处理)两批文件构成1.questions.list : 题目列表不需要题目的内容2.需要题目的描述题面、题目的预设代码(header.cpp)、测试用例代码(tail.cpp)这两个内容是通过编号来进行关联的。(1)当用户提交自己代码的时候header.cpp#includeiostream#includevector#includestring#includemap#includealgorithmusingnamespacestd;classSolution{public:boolisPalindrome(intx){// 将你的代码写在下面// code// code// ......returntrue;}};(2)OJ不是只把上面这段代码提交给compile_and run而是和测试用例代码文件(tail.cpp)一起交给compile_and runtail.cpp下面这三行宏下我们不想让编译器编译的时候保留它而是裁剪掉g -D COMPILER_ONLINE仅仅是为了让我们设计测试用例的时候不要报错#ifndefCOMPILER_ONLINE#includeheader.cpp#endifvoidTest1(){// 通过定义临时对象来完成方法的调用boolresultSolution().isPalindrome(121);if(result){std::cout通过用例1, 测试121通过 ... OK!std::endl;}else{std::cout没有通过用例1, 测试的值是: 121std::endl;}}voidTest2(){boolresultSolution().isPalindrome(-10);if(!result){std::cout通过用例2, 测试-10通过 ... OK!std::endl;}else{std::cout没有通过用例2, 测试的值是: -10std::endl;}}intmain(){Test1();Test2();return0;}(3)oj_model功能设计根据题目list, 加载所有的题目信息到内存中model: 主要用来和数据进行交互, 对外提供访问数据的接口需要使用boost库中的spilt方法进行字符串切分安装boost库sudo apt install libboost-all-dev(4)oj control功能设计数据渲染ctemplate是一个由 Google 最初开发现在由社区维护的 C 网页渲染库。它的核心作用是将程序的逻辑代码和最终要展示的文本内容分离开。它的一个主要应用场景是在C程序里生成动态的 HTML 网页。安装ctemplate先将压缩包解压或者git克隆到云服务器再执行下面命名一步一步来./autogen.sh./configuresudo makesudo make install编译时需要加上-lctemplate -lpthread2.1 建立文件版题库 2.2 建立MySQL版题库在数据库中设计可以远程登录的MySQL用户并赋权 — ojclinet_create user oj_client‘%’ identified by ‘dqwanAB987123456’; — 创建grant all on oj.* to oj_client‘%’; — 赋权创建库创建并设计表结构 — 数据库oj表ojquestionscreate database oj; — 创建oj数据库开始编码 — 连接并访问数据库连接数据库 — 使用第三方库mysql-connector-c-6.1.11-linux-glibc2.12-x86_64