Linux搭建在线OJ服务器

在线OJ服务器

    • 简介
      • 界面预览
    • 使用框架
      • httplib
      • ctemplate
    • 前端
      • all_questions
      • question
    • 服务器搭建
      • oj_server.cpp
        • 在线编程下的GET和POST请求处理逻辑
          • GET
          • POST
      • oj_model.hpp
        • TestQues结构体
        • OjModel类
          • GetAllQuestions
          • GetOneQuestion
      • tools.hpp
        • StringTools类
        • FileOpen类
        • UrlUtil类
      • oj_view
      • compile
        • 编译处理
    • 源代码
    • 可能出现的问题

简介

Linux网络编程,仿照牛客网,搭建在线OJ网站服务器,实现选择题目,并进行对应题目的在线编程提交给服务器,并在服务器中验证编译结果,再返回给浏览器。
由于在线oj的测试用例难以获取,所以目前只有一道题目


界面预览

图片仅作为页面填充
主页面
Linux搭建在线OJ服务器_第1张图片
在线编译页面
Linux搭建在线OJ服务器_第2张图片


使用框架

httplib

cpp-httplib,一个header-only的第三方框架,封装了http协议,使用起来十分方便,只需要包含其头文件即可

https://github.com/yhirose/cpp-httplib

ctemplate

ctemplat是一个进行html渲染,实现视图与配置内容的分离,通过 {{ }} 占位符进行替换,能够根据程序动态变化页面中所要显示的内容。


前端

因为博主只是简单学习过前端知识,HTML,CSS,JS多少会一点,所以所使用的前端技术都是基础。

all_questions


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>在线OJtitle>
    <link href="all_q.css" rel="stylesheet" type="text/css">
head>
<body>
<div id="header"><img src="./img/title.png">div>
<div style="position: relative; top:20px; left: 15%;margin-bottom: 20px">首页>在线编程>剑指offerdiv>
<div id="content">
        <div id="intro"><h2 style="margin-bottom: 10px">专题训练h2>
            <p style="margin: 20px">
                该专题为剑指offer专题,题目均来自《剑指offer》,里面每道题带有练习模式和考试模式,可还原考试模式进行模拟,也可通过练习模式进行练习。
            p>
        div>
        <div id="questions">
            <table>
                <tr>
                    <th style="width: 50px">题号th>
                    <th style="width: 160px">考点th>
                    <th style="width: 320px">题目th>
                    <th style="width: 100px">难度th>
                    <th style="width: 80px">通过率th>
                tr>
                {{#question}}
                <tr>
                    <td>{{id}}td>
                    <td>{{family}}td>
                    <td><a href="/question/{{id}}">{{name}}a>td>
                    <td>{{difficulty}}td>
                    <td>{{percent}}td>
                tr>
                {{/question}}
            table>
        div>
div>
<div id="else">
    <div id="t">
        <h3 style="display: inline;margin: 10px; width:15px" >
        <script type="text/javascript">
            var out = document.getElementById("t");
            var t = new Date();
            var arr = new Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六");
            document.write(arr[t.getDay()]);
            document.write("
"
); document.write(" "+(t.getMonth()+1)+"-"+t.getDate());
script> h3> div> <div id="scult">div> <h3 style="text-align: center;margin-top: 5px">求职小鱼h3> div> body> html>

这里的{{#question}} {{/question}}是用来定义子区域,通过ctemplate渲染后能够实现循环输出区域内的内容。

css就不多作介绍感兴趣可以去git上查看源码

通过改变页面中各个标签的浮动,实现像图片中各个小区域,类似瀑布流的显示效果

当中的JS代码仅是用来获取当前日期


question


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>在线编程title>
    <link rel="stylesheet" href="one_q.css" type="text/css">
head>
<body>
<div class="detail">
    <div id="intro"><pre>时间限制:C/C++ 1秒,其他语言2秒  空间限制:C/C++ 256M,其他语言512M

热度指数:4692

    pre>div>
    <h3>题目描述h3>
    <p id="desc">{{desc}}p>
    <h4>示例h4>
    <div id="des">
        <p>输入p>
        <div class="print"><p>{{inp}}p>div><br>
        <p>输出p>
        <div class="print"><p>{{outp}}p>div><br>
    div>
div>
<div class="pram">
    <form action="/question/{{id}}" method="POST">
        <textarea style="height: 500px" class="inp" name="code">
            {{header}}
        textarea>
        <hr>
        <textarea style="height: 150px" class="inp">
            {{comp}}
        textarea>
        <label><div id="save"><h3 style="color: white;text-align: center;line-height: 10px">保存并调试h3>div><input type="submit" formenctype="appliaction/json" style="display: none">label>
    form>
div>
body>
html>

在线编译界面分为左右两个区域,左边区域用于显示当前问题的描述信息,是能够上下滑动的,所以将左边区域设为绝对定位,而右边黑色区域是编辑的输入框,除了textarea内部能上下滚动,整个黑色部分是不能上下移动的,所以右边的定位为fixed


服务器搭建

Linux搭建在线OJ服务器_第3张图片
代码体量也较大,所以不再博客中展示,可以在git中对照查看,跳转

oj_server.cpp

整个服务器的入口。并定义/all_questions下的GET请求处理逻辑,已经/question/re(\d+),此处通过正则表达来加载不同题目的地址,并定义其GET和POST请求的处理逻辑。

在线编程下的GET和POST请求处理逻辑

GET

get请求中获取单个题目文件夹中的所有信息,读取信息后通过模板技术填充到页面当中,GET也请求相对简单

POST

post请求,需要向服务器提交form表单中的信息
牛客网中的效果是在点击保存并调试时,在编程局域下方输出运行结果,而页面不会切换

因为博主完全不懂Ajax这类相关技术,所以想了一个偷鸡的方法,实现类似的效果

每次提交的时候,将用户提交的代码,保存到问题目录下的一个save.cpp文件当中,同样的将编译运行结果也存放在一个result.txt文件中
每次提交时重新渲染一次页面,将save.cpp与result.txt中的内容与{{header}}和{{comp}}替换来实现类似效果
效果如下
Linux搭建在线OJ服务器_第4张图片

oj_model.hpp

加载问题中的所相关内容

TestQues结构体

定义结构体,用于存放题目的相关信息,名称,路径等

OjModel类

类中通过unordered_map的关联索容器存放题目信息,因为unordered_map底层的哈希结构,查找效率十分高效。

GetAllQuestions

读取conf文件中的信息并存放在map中,并按照id排序,升序显示,该方法主要用来显示所有问题。


GetOneQuestion

出参,通过id在map中查找到对应题目的路径,通过FileOpen::ReadDataFromFile工具类中的方法读取对应文件中的内容,并通过参数传出。


tools.hpp

自己封装的读写文件的工具类

StringTools类

通过boost库中的split方法,可让读取的内容按要求分开,并存放到vector


FileOpen类

封装的两个静态方法读写文件,不多介绍


UrlUtil类

这个是在网上找的解析url请求正文中的内容的封装类


oj_view

模板类技术的封装,主要用于填充all_questions.html和question.html页面中的内容

ctemplate的使用,首先定义一个TemplateDictionary的字典
使用SetValue的方法,将html中的占位符与变量中的内容替换,最后打开Template* 的操作句柄打开html文件,与打开文件类似,使用Expand方法,将替换后的html文件以字符串的形式传出函数。

all_questions的唯一不同是有一个{{/question}}这样的子区域,需要在循环中替换占位符,所以每次循环都要定义一个AddSectionDictionary的指针。

compile

编译运行模块

编译处理

每一个文件的路径中,都有一个tail.cpp的处理程序,浏览器提交的程序,与tail中的main函数合为一个cpp文件,然后fork出一个子进程,子进程通过execv进程程序替换,g++编译处理,生成并打开一个tmp文件存放到tmp路径下,dup2重定向,将编译的标准输出重定向到tmp文件当中,就可以保存编译的错误信息。


源代码

https://github.com/akh5/Linux/tree/master/OJ1.2


可能出现的问题

在这里插入图片描述
因为httplib的构造使用了正则表达式,而gcc4.8的正则表达式有bug,所以可能导致gcc编译得到的可执行文件,一旦运行就有可能抛出如图所示的正则表达式异常,而导致无法运行。

所以在编译前需要启动gcc的版本升级

source /opt/rh/devtoolset-4/enable


程序运行后,ip地址无法访问,大概率是linux防火墙导致
所以程序运行前需要先关闭防火墙

systemctl stop firewalld

你可能感兴趣的:(Linux)