C++ -- 负载均衡式在线OJ (三)

[复制链接]
发表于 2026-2-9 13:08:33 | 显示全部楼层 |阅读模式
前面部分请看这里C++ – 负载均衡式在线OJ (二)

  四、oj_server模块

   oj_server说白了就是一个网站。oj_server的功能如下
  
      
  • 1.获取首页  
  • 2.获取标题列表  
  • 3.获取单道标题,并提供编辑功能  
  • 4.提交判题功能(背后依赖的就是提供编译运行服务的服务器
   我们想采取的是基于MVC的一种架构模式
  
      
  • M model 与数据交互的模块  
  • V view 视图,指用户界面,就是用来与用户举行交互的,模块  
  • C controller 控制器,焦点的业务逻辑都在这里实现,公道调配model和view模块。
oj_server负担的就是负载均衡式的去调用后端的一个个编译服务,然后显现给用户,以是oj_server更靠近用户
1. oj_server的功能路由

我们操持的oj_server一共能提供给用户的是3个功能路由

      
  • 1.标题列表的功能路由  
  • 2.单道标题标功能路由  
  • 3.提交代码举行判题的功能路由
  1. #include <iostream>
  2. #include <signal.h>
  3. #include "../comm/httplib.h"
  4. #include "oj_control.hpp"
  5. using namespace httplib;
  6. using namespace ns_control;
  7. static Control *ctrl_ptr = nullptr;
  8. void Recovery(int signo)
  9. {
  10.    
  11.    
  12.     ctrl_ptr->RecoveryMachine();
  13. }
  14. int main()
  15. {
  16.    
  17.    
  18.     signal(SIGQUIT, Recovery);
  19.     //用户请求的服务路由功能
  20.     Server svr;
  21.     Control ctrl;// 当用户请求时就直接调用controller当中的方法,交互数据model也被controller包含在内
  22.     ctrl_ptr = &ctrl;
  23.     // 获取所有的题目列表
  24.     svr.Get("/all_questions", [&ctrl](const Request &req, Response &resp){
  25.    
  26.    
  27.         //返回一张包含有所有题目的html网页
  28.         std::string html;
  29.         ctrl.AllQuestions(&html);
  30.         //用户看到的是什么呢??网页数据 + 拼上了题目相关的数据
  31.         resp.set_content(html, "text/html; charset=utf-8");
  32.     });
  33.     // 用户要根据题目编号,获取题目的内容
  34.     // /question/100 -> 正则匹配
  35.     // R"()", 原始字符串raw string,保持字符串内容的原貌,不用做相关的转义
  36.     svr.Get(R"(/question/(\d+))", [&ctrl](const Request &req, Response &resp){
  37.    
  38.    
  39.         std::string number = req.matches[1];
  40.         std::string html;
  41.         ctrl.Question(number, &html);
  42.         resp.set_content(html, "text/html; charset=utf-8");
  43.     });
  44.     // 用户提交代码,使用我们的判题功能(1. 每道题的测试用例 2. compile_and_run)
  45.     svr.Post(R"(/judge/(\d+))", [&ctrl](const Request &req, Response &resp){
  46.    
  47.    
  48.         std::string number = req.matches[1];
  49.         std::string result_json;
  50.         ctrl.Judge(number, req.body, &result_json);
  51.         resp.set_content(result_json, "application/json;charset=utf-8");
  52.         // resp.set_content("指定题目的判题: " + number, "text/plain; charset=utf-8");
  53.     });
  54.    
  55.     // 设置Web根目录
  56.     svr.set_base_dir("./wwwroot");
  57.     // 启动服务器
  58.     svr.listen("0.0.0.0", 8080);
  59.     return 0;
  60. }
复制代码
注意:

      
  • 1.set_base_dir实在是提供给首页的,我们的url假如是http://101.42.249.66/的话就代表想要的资源是/,这个实在就代表的是访问的我们的web根目次(我们定名为wwwroot),而一样寻常,如许的访问代表首页,我们会在web根目次下放置一个index.html供用户访问
      
  • 2.R"()"上面以及说过了,就是row string,保持()中字符串原貌。
      
  • 3.然后(\d+)代表的是正则表达式,+代表有多少就匹配多少,\d是匹配数字
      
  • 4.上面使用到了Request当中的mathes对象,实在matches对象就是将我们的资源申请做了切分,好比说\question\100,question就放到了matches[0],100就放到了matches[1]当中。

   我们提供了三个功能路由就分别对应三种资源申请
  
      
  • http://110.42.249.66:8080/all_questions


      
  • http://110.42.249.66:8080/question/1

2. 创建文件版的题库

起首,我们的标题必要的东西有

      
  • 1.题号 number  
  • 2.标题 title  
  • 3.难度 star  
  • 4.形貌 desc  
  • 5.时间要求 cpu_limit  
  • 6.空间要求 mem_limit
在oj_server目次下,我们必要一个questions目次对标题标全部东西举行存储
而我们必要一个questions.list设置文件来读取全部标题(我们操持将标题构建成一个Question对象)
然后更具体的东西,好比标题标形貌,预设给用户的代码,测试用例单独放在一个目次里

   在questions.list设置文件中的存储方式
  

   header.cpp
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5. class Solution
  6. {
  7.    
  8.    
  9. public:
  10.     int Max(const vector<int> &v)
  11.     {
  12.    
  13.    
  14.         //将你的代码写在下面
  15.         return 0;
  16.     }
  17. };
复制代码
  tail.cpp测试用例部分
  以是我们必要给header.cpp中的代码举行归并,举行归并的代码就放在tail.cpp当中
所谓测试用例,实在就是把你在代码编辑框中的代码提交上来,然后和别的一个代码举行归并。这个代码里差的就是对你写的那部分函数。以是两个合在一起,才形成了完备的一个步调。
  1. #ifndef COMPILER_ONLINE
  2. #include "header.cpp"
  3. #endif
  4. void Test1()
  5. {
  6.    
  7.    
  8.     vector<int> v = {
  9.    
  10.    1, 2, 3, 4, 5, 6};
  11.     int max = Solution().Max(v);
  12.     if (max == 6)
  13.     {
  14.    
  15.    
  16.         std::cout << "Test 1 .... OK" << std::endl;
  17.     }
  18.     else
  19.     {
  20.    
  21.    
  22.         std::cout << "Test 1 .... Failed" << std::endl;
  23.     }
  24. }
  25. void Test2()
  26. {
  27.    
  28.    
  29.     vector<int> v = {
  30.    
  31.    -1, -2, -3, -4, -5, -6};
  32.     int max = Solution().Max(v);
  33.     if (max == -1)
  34.     {
  35.    
  36.    
  37.         std::cout << "Test 2 .... OK" << std::endl;
  38.     }
  39.     else
  40.     {
  41.    
  42.    
  43.         std::cout << "Test 2 .... Failed" << std::endl;
  44.     }
  45. }
  46. int main()
  47. {
  48.    
  49.    
  50.     Test1();
  51.     Test2();
  52.     return 0;
  53. }
复制代码
注意:

      
  • 条件编译的缘故原由是:这部分代码由于缺少用户提交的那部分函数,以是我们在编译oj_server的时间,是会报错的,由于少了函数,跑不了可以明确。以是我们必要加一个条件编译,让这个.cc文件知道我们有该函数,不要报错。  
  • 这个条件编译到时间我们再通过给其他方式去掉,我们可以在调用g++的时间加选项,好比我们上面的宏是 COMPILER_ONLINE,那么到时间,我们直接 gcc … -D COMPILER_ONLIEN就可以去掉了。-D选项就是在下令行举行宏界说的方式
3. model模块

   model模块紧张是用来和数据交互的,对外提供访问数据的接口
  我们在model模块当中,由于我们的数据就是标题,以是一上来我们就要把标题读出来。
我们会有一个Question类,用它来形貌该标题标信息
  1. // 根据题⽬list⽂件,加载所有的题⽬信息到内存中
  2. // model: 主要⽤来和数据进⾏交互,对外提供访问数据的接⼝
  3. namespace ns_model
  4. {
  5.    
  6.    
  7.     using namespace std;
  8.     using namespace ns_log;
  9.     using namespace ns_util;
  10.     struct Question
  11.     {
  12.    
  13.    
  14.         std::string number; // 题⽬编号,唯⼀
  15.         std::string title;  // 题⽬的标题
  16.         std::string star;   // 难度: 简单 中等 困难
  17.         int cpu_limit;      // 题⽬的时间要求(S)
  18.         int mem_limit;      // 题⽬的空间要去(KB)
  19.         std::string desc;   // 题⽬的描述
  20.         std::string header; // 题⽬预设给⽤⼾在线编辑器的代码
  21.         std::string tail;   // 题⽬的测试⽤例,需要和header拼接,形成完整代码
  22.     };
  23. }
复制代码
选择用unordered_map<string,Question>的结构体来存储天生的Question,创建标题(字符串)与Question的映射。
   使用boost准标准库当中的split举行字符串分割
  1. class StringUtil
  2. {
  3.    
  4.    
  5. public:
  6.       /**
  7.        * str:输入性参数,要切分的字符串
  8.        * target:输出型参数,保存并返回切分完毕的结果
  9.        * sep:separator分隔符
  10.        */
  11.        static void SplitString(const std::string &str,std::vector<std::string>* target,std::string sep)
  12.        {
  13.    
  14.    
  15.            //使用C++准标准库boost   当中的split进行字符串分割
  16.            boost::split((*target),str,boost::is_any_of(sep),boost::algorithm::token_compress_on);
  17.            //is_any_of代表sep分隔符字符串当中的任意一个字符都能用来分割
  18.            //token_compress_on代表我是否需要进行压缩
  19.            //调用这个接口就自动的帮我们完成了字符串切分
  20.         }
  21.     };
复制代码
按行读取设置文件形成Question对象

      
  • 1.用C++的文件流的方式创建ifstream对象,打开文件流  
  • 2.使用getline举行按行读取,getline的注意事项上面以及说过,不再重复  
  • 3.使用字符串工具类中封装好的函数举行字符串切割放入tokens数组  
  • 4.使用该数组举行Question结构体的创建
  1. // 根据题⽬list⽂件,加载所有的题⽬信息到内存中
  2. // model: 主要⽤来和数据进⾏交互,对外提供访问数据的接⼝
  3. namespace ns_model
  4. {
  5.    
  6.    
  7.     using namespace std;
  8.     using namespace ns_log;
  9.     using namespace ns_util;
  10.     const std::string questins_list = "./questions/questions.list";
  11.     const std::string questins_path = "./questions/";
  12.     class Model
  13.     {
  14.    
  15.    
  16.     private:
  17.         // 题号:题目细节
  18.         unordered_map<string, Question> questions;
  19.     public:
  20.         Model()
  21.         {
  22.    
  23.    
  24.             assert(LoadQuestionList(questins_list));
  25.         }
  26.         bool LoadQuestionList(const string &question_list)
  27.         {
  28.    
  29.    
  30.             // 加载配置⽂件: questions/questions.list + 题⽬编号⽂件
  31.             ifstream in(question_list);
  32.             if (!in.is_open())
  33.             {
  34.    
  35.    
  36.                 LOG(FATAL) << " 加载题库失败,请检查是否存在题库⽂件" << "\n";
  37.                 return false;
  38.             }
  39.             string line;
  40.             while (getline(in, line))
  41.             {
  42.    
  43.    
  44.                 vector<string> tokens;
  45.                 StringU
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表