关于在线OJ训练营项目的设计思路

Posted 哦哦呵呵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于在线OJ训练营项目的设计思路相关的知识,希望对你有一定的参考价值。

目录

1. 项目描述

  该系统类似于LeetCode的代码练习功能,提供了一个用户可以在线编写代码并且能够进行编译的环境,在编写代码的同时提供了语法纠错、代码高亮、自动补全等基本功能。
  用户可以通过域名访问服务器,系统内置了多道编程题,用户点击对应题目就可以进行练习。并且题目内含有大量测试样例,服务器会根据用户代码会进行用例的测试,检测用户代码是否符合题意。并且可以将编译出错的原因返回给用户端。

2. 模块

2.1 在线编译器模块

  能够将网页中用户输入的代码内容放入服务器中,并进行编译,运行,比对结果。

实现功能

  • 获取需要编译代码的临时文件
  • 调用g++进行编译,将编译结果进行存储
  • 如果文件编译错误或运行时错误,需要记录到文件中去
  • 运行可执行文件,执行测试用例代码,将运行结果进行记录
  • 将记录结果发送给客户端

2.2 题目管理模块

  管理当前系统中的所有OJ题目及具体题目描述,用例代码。页面以列表形式显示所管理的题目,并且用户点击题目可以跳转到详情页进行代码的编写及提交。

具体功能

  • 获取所有的题目列表 /all_question
  • 点击指定题目,可以获取题目的详细内容,并且可以书写代码 /quesion
  • 调用在线编译模块进行编译和运行 /compile
  • 解析运行结果,如果正确返回正确结果,如果错误返回错误情况 result

2.3 工具模块

  该模块提供了许多具体工具,可以提高开发效率。

具体工具

  • 时间戳工具: 用来生成不重复文件名
    文件名: tmp_ + “时间戳” + 序号 + ‘.类型’ (保证了文件名的唯一性)
  • 日志打印工具: 用来记录代码执行记录
  • 文件读写功能: 重新封装文件读写函数,方便使用
  • URL解析模块: 使用boost库提供的函数进行解析,解析出有效载荷,分离出用户提交代码与用户输入。

3. 模块实现细节

3.1 在线编译

3.1.1 搭建HTTP服务器

  使用第三方库HttpLib进行搭建,搭建出的服务器支持多连接。通过库中的函数进行请求的接收与响应。

server.Post("/compile", [](const Request& req, Response& resp) 

);
server.listen("0.0.0.0", 9081);

3.1.2 JSON组织请求与响应

  使用JSON进行请求与相应的组织,因为http中传来的数据是结构化的数据,将该数据进行序列化,而JSON可以简单且高校的组织结构化数据,并且以键值对的形式进行组织。
  网络中传输更加方便,并且可以与HTTP无缝衔接。

使用JSON组织请求和响应的格式:

此处看到的请求参数和响应结果格式为
请求
	"code": "#include....."
	"stdin": "hello"


响应
	"error": 0结果正常, 1编译错误, 2运行错误, 3其它错误
	"reason": "",错误原因
	"stdout": "hello",
	"stderr": "",

3.1.3 处理请求生成响应

  用户编写完成代码之后,将代码通过POSTGET的方式将内容提交给服务器,服务器就需要进行请求的解析,来处理数据。
  但是浏览器在发送请求时,可能会携带多组数据,所以在服务端就需要解析客户端发来的多组数据,提取出存储代码的字段交给编译模块进行处理,并且浏览器会对有效载荷中的字符进行转义,还需要将转义后的字符转义回来。
  以上操作执行完之后,才可以调用编译模块进行代码的处理。

3.1.4 编译模块对代码的处理

  在这一部分已经拿到了,用户提交的代码,根据代码编译出可执行程序,就需要服务器生成临时文件存储源代码,才能进行编译。
  并且在编译或运行过程中,可能会出现错误,所以需要记录过程中可能会出现问题的记录信息。
  编译成功调用可执行程序,将标准输入记录到文件中,把文件中的内容重定向给可执行程序,可执行文件的标准输出也重定向到文件中,方便后期使用。

步骤

  • 根据json请求对象,生成源代码文件和标准输入文件
  • 调用g++进行编译(fork + exec), 生成一个可执行程序,如果编译出错需要记录下来(重定向到文件)
  • 调用可执行程序,把标准输入记录到文件中,把文件中的内容重定向给可执行程序,可执行程序的标准输出重定向至文件
  • 把程序中的最终结果进行返回,构造resp_json对象

编译过程

  • 先构造出编译指令 g++ file_name.cpp -o file_name.exe -std=c++11
  • 创建子进程
  • 父进程等待子进程退出,防止出现僵尸进程
  • 子进程进行程序替换,将标准错误重定向至编译时出错的文件中.
  • 编译完成后,通过stat()函数判断可执行文件是否生成。生成代表编译成功。

// 4.子进程进行程序替换
// 将编译时错误的信息输出到文件中
int fd = open(CompileErrorPath(file_name).c_str(), O_WRONLY | O_CREAT, 0666);
if (fd < 0)

    LOG(ERROR) << "Open Compile file error" << std::endl;
    exit(1);

// 将文件描述符中的标准错误的内容,拷贝至文件中
dup2(fd, 2);

execvp(command[0], command);

// 此处子进程执行失败直接退出
exit(0);

注意:上方程序中先进行了文件描述符的重定向,再进行的进程替换,注意进程替换只会替换程序的代码段和数据段。不会替换PCB,而PCB中存储文件描述符,所以不会影响重定向关系

执行可执行程序
  创建子进程,并且将可执行程序的标准输入、标准输出、标准错误重定向到文件中,记录可执行程序执行的每一个细节。

3.2 题目管理

采用MVC的结构进行管理题目

Model: 题目的描述结构
View: 网页的显示内容
Controller: 负责逻辑处理

3.2.1 如何描述题目(Model)

哪些信息可以描述一个题目

基本结构如上图,在此项目中采用文件的形式进行组织

基于文件的方式完成文件的存储

  • 约定每一个题目对应一个目录,目录的名字就是题目的id.
    目录包含以下几个文件:
    1.header.cpp 代码矿建
    2.tail.cpp 代码测试用例
    3.desc.txt 题目详细描述
  • 使用一个oj_config.cfg文件啊,作为一个总的入口文件,这个文件是一个行文本文件.这个文件的每一行对应一个需要被服务器加载起来的题目,一行里面包含以下几个信息: 题目id,题目名字,题目难度,题目对应目录

3.2.2 题目信息加载 (Model)

  题库中的题目是很多的,需要将题库中的信息进行组织,通过map将题目信息全部组织进去,在all_questions页面中进行题目列表的展示。

  • 先打开oj_config.cfg文件
  • 按行读取 oj_config.cfg文件,并进行解析,一行包含4个字段,字段间的分隔是 \\t
  • 根据解析结果拼装成 Question结构体
  • 把结构体加入到map中

上面将题目加载到了内存中,只需要遍历map就可以有序的取出所有题目了。

获取某个具体题目,需要传入题目id,通过在map中检索id,就可以拿到题目详情。

3.2.3 渲染页面(View)

  上一步获取到题目列表后,就需要将列表显示出来生成html页面,这一过程叫做渲染。在渲染过程用用到了google的开源库ctemplate模板库,帮助我们构建页面。
  在oj_view.hpp中,添加好了网页需要填空的数值,需要一个网页来映射这些值。

   在C++代码中直接通过字符串拼接的方式构造html太麻烦, 通过网页模板的方式解决问题
  模板类似于填空题,实现准备好一个html把其中一些需要动态计算的数据挖个空留下来,处理请求过程中,根据计算结果填空

  1.先创建一个 ctemplate对象,借助这个对象完成填空过程,是总的组织的对象
  2.循环的往这个对象中添加一些子对象
  3.每一个子对象再设置一些键值对(和模板中留下的对应的)
  4.进行数据的替换,生成最终的html

3.2.3 服务程序(Controller)

作为服务器的核心逻辑,需要创建好对应的服务器框架代码,在这个框架中来组织逻辑

  • 启动服务器,加载题目信息
  • 获取题目信息,使用题目信息生成题目列表对应的HTML页面
  • 用户点击某一题后,根据题目id,进入题目详情页并且进行代码编写
  • 用户提交代码后,按照编译逻辑进行编译,将结果返回给用户。
    1.先根据id获取到题目信息
    2.解析body,获取到用户提交的代码,将Http中的body,解析成键值对,存入body_kv
    3.构造JSon结构的参数,需要编译的代码,是用户提交代码 + 题目的测试用例代码
    4.调用编译模块进行编译
    5.根据编译结果构成最终的网页

总结

以上是关于关于在线OJ训练营项目的设计思路的主要内容,如果未能解决你的问题,请参考以下文章

关于在线OJ训练营项目的设计思路

在线OJ系统

在线OJ系统

在线OJ系统

在线OJ系统

组队打代码!!!