个人主页:Lei宝啊
愿所有美好如期而遇
目录
1. 升级gcc (gcc -v查看gcc版本, 超过7就不用看本条升级gcc)
一、所用技术与开发环境
所用技术
- C++ STL 标准库
- Boost 准标准库(字符串切割)
- cpp-httplib 第三方开源网络库
- ctemplate 第三方开源前端网页渲染库
- jsoncpp 第三方开源序列化、反序列化库
- 负载均衡设计
- 多进程、多线程
开发环境
- ubuntu 5云服务器
- vscode
二、准备及库的安装
1. 升级gcc (gcc -v查看gcc版本, 超过7就不用看本条升级gcc)
对于cpp-httplib库来说,用老的编译器,要么编译不通过,要么运行报错。
安装scl来升级gcc
sudo yum install centos-release-scl scl-utils-build
sudo yum install -y devtoolset-7-gcc devtoolset-7-gcc-c++ (这里的7可以是8或者9)
scl enable devtoolset-7 bash (启动,只在本会话有效)
如果想每次登陆的时候,都是较新的gcc,需要把上面的命令添加到你的~/.bash_profile中
添加:scl enable devtoolset-7 bash
2. 安装 jsoncpp
sudo yum install -y jsoncpp-devel
3. 安装 cpp-httplib
建议:cpp-httplib 0.7.15, 码云上去找。
4. 安装boost库
sudo apt update 更新软件包
sudo apt install libboost-all-dev(博主是unbuntu)
5. 安装ctemplate
这个资源可以在这里找:https://hub.fastgit.xyz/OlafvdSpek/ctemplate
接着将资源放到服务器上,执行如下命令
./autogen.sh
./configure
make //编译
make install //安装到系统中 如果报错,加上sudo
三、项目宏观结构
- comm 模块
- compiler模块
- oj_server模块
1. leetcode结构
本项目只实现了leetcode的题目列表和刷题功能。
2. 项目宏观结构
B/S模式:浏览器-服务器(Browser-Server, B/S)模式
3. 编写思路
先写compiler服务器,接着写oj_server,最后是前端页面设计,直接copy。
四、compiler服务设计
1. 日志模块
其他模块都会引用这个模块,这个模块我们之前的文章有详细代码和讲解,我们这里不多赘述,贴出链接:日志介绍及简单实现
2. 公共方法模块
这个模块可以先直接跳过不看,当后面模块用到这个模块中的方法时返回来看。
这里介绍几个函数:gettimeofday获取时间戳,stat获取文件属性(能获取就能说明文件存在,获取不到就说明文件不存在);C++11及以上版本,支持在atomic头文件中,我们使用atomic_int类型定义的变量,有原子加、原子减、原子比较并交换、原子自增、原子自减等操作。
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <atomic>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
using namespace std;
namespace ns_commfunc
{
const string temp = "./temp/";
// 将文件名变为文件路径,并且添加后缀
class PathUtil
{
public:
static string AddSuffix(const string filename, const string suffix)
{
string ret = temp + filename + suffix;
return ret;
}
//编译模块
static string filepath_src(const string& filename)
{
return AddSuffix(filename, ".cpp");
}
static string filepath_exe(const string& filename)
{
return AddSuffix(filename, ".exe");
}
static string filepath_stderr(const string& filename)
{
return AddSuffix(filename, ".compile_err");
}
//运行模块
static string filepath_stdin(const string& filename)
{
return AddSuffix(filename, ".stdin");
}
static string filepath_stdout(const string& filename)
{
return AddSuffix(filename, ".stdout");
}
static string filepath_stderr_runner(const string& filename)
{
return AddSuffix(filename, ".stderr");
}
};
class TimeUtil
{
public:
static string Gettimeofms()
{
struct timeval tv;
gettimeofday(&tv, nullptr);
string ret = to_string(tv.tv_sec * 1000 + tv.tv_usec / 1000);
return ret;
}
};
class FileUtil
{
public:
static bool Isexist_file(const string filename)
{
struct stat temp;
int ret = stat(filename.c_str(), &temp);
return ret == 0 ? true : false;
}
static string UniqueFilename()
{
static atomic_uint id(0);
id++;
return TimeUtil::Gettimeofms() + "_" + to_string(id);
}
static bool WritecodeToFile(const string filename, const string& content)
{
ofstream out(filename);
if(!out.is_open()) return false;
out.write(content.c_str(), content.size());
return true;
}
static bool Readfile(const string& filename, string& content, bool keep)
{
ifstream in(filename);
if(!in.is_open()) return false;
string line;
while(getline(in, line))
{
content += line;
content += keep ? "\n" : "";
}
return true;
}
static string CodeTodesc(int status, string filename)
{
string ret = "";
switch (status)
{
case 0:
ret = "运行正常";
break;
case -1:
ret = "代码为空";
break;
case -2:
ret = "未知错误";
break;
case -3:
// ret = "编译错误";
FileUtil::Readfile(filename, ret, true);
break;
case 24:
ret = "超时";
default:
ret = "待填充";
break;
}
return ret;
}
};
}
3. 编译模块
1. 创建编译类Compile,封装在命名空间ns_compile中:
namespace ns_compile
{
class Compile
{
private:
public:
Compile()
{}
~Compile()
{}
};
}
2. 写一个方法,完成编译功能,那么这个方法的参数和返回值我们如何设置?我们要明白,外面有一个整合模块来接收请求,并且从请求中提取代码并解析成字符串形成源文件,也就是说,我们的编译方法,参数为这个文件名,也就是字符串类型。返回值可以设置为bool类型,表示是否编译成功。
/*
@return val: 编译结果是否成功
@pragma : 文件名
*/
static bool compile(const string& filename)
{}
接下来就可以创建子进程,按照我们上面的逻辑写代码了:
其中,我们在comm文件夹下,创建了一个公共方法文件,这个文件中我们写不同模块需要使用的公共方法,这些方法封在ns_commfunc中的不同类中,有Path类,这个类中的方法用来形成文件路径;文件类,这个类中的方法用来对文件进行操作。
static bool compile(const string& filename)
{
int id = fork();
if(id < 0)
{
Log(ERROR, "子进程创建失败");
return false;
}
else if(id == 0)
{
//子进程
//重定向
umask(0);
i
标签:负载,return,OJ,在线,filename,static,模块,const,string
From: https://blog.csdn.net/m0_74824254/article/details/141898224