Skip to content

Commit

Permalink
负载均衡式在线oj系统完成
Browse files Browse the repository at this point in the history
  • Loading branch information
sjmshsh committed Jan 14, 2023
1 parent d0a55b5 commit 5395d67
Show file tree
Hide file tree
Showing 204 changed files with 31,173 additions and 0 deletions.
6,708 changes: 6,708 additions & 0 deletions comm/httplib.h

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions comm/log.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include <iostream>
#include <string>
#include "util.hpp"

namespace ns_log
{
using namespace ns_util;
// 日志等级
enum
{
INFO, // 就是整数
DEBUG,
WARNING,
ERROR,
FATAL
};

// LOG() << "message"
inline std::ostream &Log(const std::string &level, const std::string &file_name, int line)
{
// 添加日志等级
std::string message = "[";
message += level;
message += "]";
// 添加报错文件名称
message += "[";
message += file_name;
message += "]";
// 添加报错行
message += "[";
message += std::to_string(line);
message += "]";

// 日志时间戳
message += "[";
message += TimeUtil::GetTimeStamp();
message += "]";

// cout 本质内部是包含缓冲区的
std::cout << message; // 不要endl进行刷新
return std::cout;
}

// LOG(INGO) << "message" << "\n"
// 开放式日志
#define LOG(level) Log(#level, __FILE__, __LINE__)
}
148 changes: 148 additions & 0 deletions comm/util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <atomic>
#include <fstream>
#include <unistd.h>
#include <vector>
#include <sys/time.h>
#include <boost/algorithm/string.hpp>

namespace ns_util
{
class TimeUtil
{
public:
static std::string GetTimeStamp()
{
struct timeval _time;
gettimeofday(&_time, nullptr);
return std::to_string(_time.tv_sec);
}

// 获得毫秒时间戳
static std::string GetTimeMs()
{
struct timeval _time;
gettimeofday(&_time, nullptr);
return std::to_string(_time.tv_sec * 1000 + _time.tv_usec / 1000);
}
};
const std::string temp_path = "./temp/";
class PathUtil
{
public:
static std::string AddSuffix(const std::string &file_name, const std::string &suffix)
{
std::string path_name = temp_path;
path_name += file_name;
path_name += suffix;
return path_name;
}
// 构建源文件路径+后缀的完成文件名
// 1234 -> ./temp/1234.cpp

// 编译时产生的临时文件
static std::string Src(const std::string &file_name)
{
return AddSuffix(file_name, ".cpp");
}
// 构建可执行程序的完成路径+后缀名
static std::string Exe(const std::string &file_name)
{
return AddSuffix(file_name, ".exe");
}
static std::string CompilerError(const std::string &file_name)
{
return AddSuffix(file_name, ".compile_error");
}

// 运行时产生的临时文件
// 构建该程序对应的标准错误完成的路径+后缀名
static std::string Stderr(const std::string &file_name)
{
return AddSuffix(file_name, ".strerr");
}
static std::string Stdin(const std::string &file_name)
{
return AddSuffix(file_name, ".stdin");
}
static std::string Stdout(const std::string &file_name)
{
return AddSuffix(file_name, ".stdout");
}
};

class FileUtil
{
public:
static bool IsFileExists(const std::string path_name)
{
struct stat st;
if (stat(path_name.c_str(), &st) == 0)
{
// 获取属性成功,文件已经存在
return true;
}
return false;
}

static std::string UniqFileName()
{
static std::atomic_uint id(0);
id++;
// 毫秒级时间戳+原子性递增唯一值:来保证唯一性
std::string ms = TimeUtil::GetTimeMs();
std::string uniq_id = std::to_string(id);
return ms + "_" + uniq_id;
}

static bool WriteFile(const std::string &target, const std::string &content)
{
// 把流打开
std::ofstream out(target);
if (!out.is_open())
{
return false;
}
out.write(content.c_str(), content.size());
out.close();
return true;
}

static bool ReadFile(const std::string &target /*可能还需要其他参数*/, std::string *content, bool keep = false)
{
(*content).clear();
std::ifstream in(target);
if (!in.is_open())
{
return false;
}
std::string line;
// getline: 不保存行分隔符, 有些时候需要保留\n
// getline: 内部重载了强制类型转换
while(std::getline(in, line))
{
(*content) += line;
(*content) += (keep ? "\n" : "");
}
in.close();
return true;
}
};

class StringUtil
{
public:
// str输入型,目标要切分的字符串
// target: 输出型,保存切分完毕的结果
// sep: 指定的分隔符
static void SplitString(const std::string &str, std::vector<std::string> *target, std::string sep)
{
boost::split((*target), str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
}
};
}
161 changes: 161 additions & 0 deletions compile_server/compile_run.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#include "compiler.hpp"
#include "runner.hpp"
#include "../comm/log.hpp"
#include "../comm/util.hpp"
#include <signal.h>
#include <unistd.h>
#include <jsoncpp/json/json.h>
namespace ns_compile_and_run
{
using namespace ns_log;
using namespace ns_util;
using namespace ns_compiler;
using namespace ns_runner;
class CompileAndRun
{
public:
static void RemoveTempFile(const std::string &file_name)
{
// 清理文件的个数是不确定的,但是有哪些我们是知道的
std::string _src = PathUtil::Src(file_name);
if (FileUtil::IsFileExists(_src))
unlink(_src.c_str());
std::string _compiler_error = PathUtil::CompilerError(file_name);
if (FileUtil::IsFileExists(_compiler_error))
unlink(_compiler_error.c_str());
std::string _execute = PathUtil::Exe(file_name);
if (FileUtil::IsFileExists(_execute))
unlink(_execute.c_str());
std::string _stdin = PathUtil::Stdin(file_name);
if (FileUtil::IsFileExists(_stdin))
unlink(_stdin.c_str());
std::string _stdout = PathUtil::Stdout(file_name);
if (FileUtil::IsFileExists(_stdout))
unlink(_stdout.c_str());
std::string _stderr = PathUtil::Stderr(file_name);
if (FileUtil::IsFileExists(_stderr))
unlink(_stderr.c_str());
}
// code > 0 : 进程收到了信号导致异常奔溃
// code < 0 : 整个过程非运行报错(代码为空,编译报错等)
// code = 0 : 整个过程全部完成
// 待完善
static std::string CodeToDesc(int code, const std::string &file_name)
{
std::string desc;
switch (code)
{
case 0:
desc = "编译运行成功";
break;
case -1:
desc = "提交的代码是空";
break;
case -2:
desc = "未知错误";
break;
case -3:
// desc = "代码编译的时候发生了错误";
FileUtil::ReadFile(PathUtil::CompilerError(file_name), &desc, true);
break;
case SIGABRT: // 6
desc = "内存超过范围";
break;
case SIGXCPU: // 24
desc = "CPU使用超时";
break;
case SIGFPE: // 8
desc = "浮点数溢出";
break;
default:
desc = "未知: " + std::to_string(code);
break;
}
return desc;
}
/***************************************
* 输入:
* code: 用户提交的代码
* input: 用户给自己提交的代码对应的输入,不做处理
* cpu_limit: 时间要求
* mem_limit: 空间要求
*
* 输出:
* 必填
* status: 状态码
* reason: 请求结果
* 选填:
* stdout: 我的程序运行完的结果
* stderr: 我的程序运行完的错误结果
*
* 参数:
* in_json: {"code": "#include...", "input": "","cpu_limit":1, "mem_limit":10240}
* out_json: {"status":"0", "reason":"","stdout":"","stderr":"",}
* ************************************/
static void Start(const std::string &in_json, std::string *out_json)
{
Json::Value in_value;
Json::Reader reader;
reader.parse(in_json, in_value); // 最后在处理差错问题
std::string code = in_value["code"].asString();
std::string input = in_value["input"].asString();
int cpu_limit = in_value["cpu_limit"].asInt();
int mem_limit = in_value["mem_limit"].asInt();
int status_code = 0;
Json::Value out_value;
int run_result = 0;
std::string file_name; // 需要内部形成的唯一文件名
if (code.size() == 0)
{
status_code = -1; // 代码为空
goto END;
}
// 形成的文件名只具有唯一性,没有目录没有后缀
// 毫秒级时间戳+原子性递增唯一值: 来保证唯一性
file_name = FileUtil::UniqFileName();
// 形成临时src文件
if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
{
status_code = -2; // 未知错误
goto END;
}
if (!Compiler::Compile(file_name))
{
// 编译失败
status_code = -3; // 代码编译的时候发生了错误
goto END;
}
run_result = Runner::Run(file_name, cpu_limit, mem_limit);
if (run_result < 0)
{
status_code = -2; // 未知错误
}
else if (run_result > 0)
{
// 程序运行崩溃了
status_code = run_result;
}
else
{
// 运行成功
status_code = 0;
}
END:
out_value["status"] = status_code;
out_value["reason"] = CodeToDesc(status_code, file_name);
if (status_code == 0)
{
// 整个过程全部成功
std::string _stdout;
FileUtil::ReadFile(PathUtil::Stdout(file_name), &_stdout, true);
out_value["stdout"] = _stdout;
std::string _stderr;
FileUtil::ReadFile(PathUtil::Stderr(file_name), &_stderr, true);
out_value["stderr"] = _stderr;
}
Json::StyledWriter writer;
*out_json = writer.write(out_value);
RemoveTempFile(file_name);
}
};
}
Binary file added compile_server/compile_server
Binary file not shown.
Loading

0 comments on commit 5395d67

Please sign in to comment.