该模块为编译运行功能,该模块需要使用json库,首先安装json,作用是将结构化的数据转化为字符串,做序列化和反序列化工作

命令:sudo yum install jsoncpp-devel

整体逻辑

image.png

Start函数

1
static void Start(const std::string &in_json, std::string *out_json){}

Start函数参数

start函数的两个参数

  • in_json: {“code”: “#include …”, “input”: “”, “cpu_limit”: 1, “mem_limit”:10240}
  • out_json: {“status”:0, “reason”:“”, “stdout”:“”, “stderr”:“”}

in_json字符串中的内容

  • code: 用户提交的代码
  • input: 用户给自己提交的代码对应的输入,暂不做处理
  • cpu_limit: 时间要求
  • mem_limit: 空间要求

out_json字符串中的内容

  • status: 状态码 (必填)
  • reason: 请求结果 (必填)
  • stdout: 程序运行完结果 (选填)
  • stderr: 运行完的错误结果

Start函数逻辑

  1. 反序列化解析in_json字符串内容
  2. 根据in_json中的内容(代码、输入、限制条件)编译运行
  3. 将编译运行期间的状态、结果、错误等信息序列化,通过输出型参数out_json输出

具体细节代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
static void Start(const std::string &in_json, std::string *out_json)
{
// 解析 in_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();

// 根据code 生成一份文件,该文件名必须要有唯一性

int status_code=0;
Json::Value out_value;
int run_result = 0;

std::string file_name; // code文件名

if(code.size()==0)
{
status_code = -1; //代表代码为空
goto END;
}


// 形成的文件名要具有唯一性,只是文件名,没有前缀路径和后缀
file_name = FileUtil::UniqFileName();

// 文件名有了,接下来是根据文件名,形成src源文件,并将code的内容写入到源文件中
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);

}

补充工具类函数

状态码解析CodeToDesc

作用:将状态码解析为对应字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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:
//代码编译时出错
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;
}

形成唯一文件名UniqFileName

1
2
3
4
5
6
7
8
9
10
11
12
//形成唯一的文件名 
//通过毫秒级时间戳+原子性递增唯一值来保证唯一性
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;

}

删除临时文件RemoveTempFile

  1. 判断文件是否存在
  2. 若存在使用unlink函数进行删除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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());
}