负载均衡式在线OJ---------第二幕

发布时间:2026/10/6 17:19:18

负载均衡式在线OJ---------第二幕 个人主页:小则又沐风个人专栏:数据结构竞赛专栏C语言CLinuxOJ项目目录前言代码与运行模块代码思路管理资源分配上限合并代码(编译和运行--引入json库)删除临时文件前言我们目前的项目知识简单的实现了代码的编译的功能,显而易见的是我们还需要代码的运行的功能.今天我们的任务就是来实现一下项目中的代码运行的模块代码与运行模块在实现这个模块之前我们需要建立起来一个共识:首先我们将用户提交的代码运行我们关心的是什么???我们这个模块并不是关心用户的代码运行是否正确.我们关心的是用户的代码是否能够运行起来.所以我们关心的就是代码运行的错误或者是正常.至于代码运行的结果是否正确就是项目的另外的模块了.(需要对运行结果和我们提供的测试用例进行比对)在确定我们运行模块的主要任务之后我们现在来编写一下我们的代码代码思路我们实现这个模块的思路还是通过创建子进程进行进程替换来完成的.代码运行的我们需要知道的是代码运行的输出结果是什么,需要知道如果代码运行出错的话错误的原因是什么.当然成熟的项目也需要提供给用户一个自测的功能.也就是需要提供一个输入的接口所以我们需要产生三个文件#pragma once #include iostream #include string #include stdio.h #include unistd.h #include fcntl.h #include unistd.h #include sys/stat.h #include sys/wait.h #include ../comm/util.hpp #include ../comm/Log.hpp using namespace LogMoudle; using namespace util; class ns_run { public: ns_run() { } ~ns_run() { } public: static int Run(const std::string file_name) { std::string std_in PathUtil::StdIn(file_name); std::string std_out PathUtil::StdOut(file_name); std::string std_error PathUtil::StdError(file_name); std::string _excute PathUtil::Exe(file_name); umask(0); int std_infd open(std_in.c_str(), O_CREAT | O_RDONLY, 0644); int std_outfd open(std_out.c_str(), O_CREAT | O_WRONLY, 0644); int std_errorfd open(std_error.c_str(), O_CREAT | O_WRONLY, 0644); int fd fork(); if (fd 0) { LOG(LogLevel::ERROR) fork error; close(std_infd); close(std_outfd); close(std_errorfd); return -1; } else if (fd 0) { dup2(std_infd, 0); dup2(std_outfd, 1); dup2(std_errorfd, 2); execl(_excute.c_str(), _excute.c_str(), nullptr); LOG(LogLevel::ERROR) execl error; exit(1); } else { int status; close(std_infd); close(std_outfd); close(std_errorfd); waitpid(fd, status, 0); LOG(LogLevel::INFO) 运行完毕 : (status 0x7F); return status 0x7f; } } };现在我们来测试一下我们的代码#includeiostream using namespace std; int main() { couthelloendl; return 0; }#include compile.hpp #includerun.hpp int main() { Compile::my_compile(code); int nns_run::Run(code); return 0; }管理资源分配上限现在我们的代码是可以做到对用户提供的代码进行编译和运行的,但是现在有一个问题就是如果有恶意的代码想要占用我们cpu的资源的代码我们的程序也会运行这个代码.在我们使用成熟的OJ的时候我们会遇到代码超时和内存超出的问题,我们也需要类似的机制来保护我们的程序,所以我们需要对用户的代码进行时间和内存分配进行限制static void SetProcLimit(int _cpu_limit, int _mem_limit) { // cpu 限制 struct rlimit cpu_rlimit; cpu_rlimit.rlim_cur _cpu_limit; cpu_rlimit.rlim_max RLIM_INFINITY; setrlimit(RLIMIT_CPU, cpu_rlimit); // 内存限制单位是kb struct rlimit mem_rlimit; mem_rlimit.rlim_max RLIM_INFINITY; mem_rlimit.rlim_cur _mem_limit * 1024; setrlimit(RLIMIT_AS, mem_rlimit); } static int Run(const std::string file_name, int _cpu_limit, int _mem_limit) { std::string std_in PathUtil::StdIn(file_name); std::string std_out PathUtil::StdOut(file_name); std::string std_error PathUtil::StdError(file_name); std::string _excute PathUtil::Exe(file_name); umask(0); int std_infd open(std_in.c_str(), O_CREAT | O_RDONLY, 0644); int std_outfd open(std_out.c_str(), O_CREAT | O_WRONLY, 0644); int std_errorfd open(std_error.c_str(), O_CREAT | O_WRONLY, 0644); int fd fork(); if (fd 0) { LOG(LogLevel::ERROR) fork error; close(std_infd); close(std_outfd); close(std_errorfd); return -1; } else if (fd 0) { dup2(std_infd, 0); dup2(std_outfd, 1); dup2(std_errorfd, 2); SetProcLimit(_cpu_limit, _mem_limit); execl(_excute.c_str(), _excute.c_str(), nullptr); LOG(LogLevel::ERROR) execl error; exit(1); } else { int status; close(std_infd); close(std_outfd); close(std_errorfd); waitpid(fd, status, 0); LOG(LogLevel::INFO) 运行完毕 : (status 0x7F); return status 0x7f; } }下面我们来介绍一个库,这个库中的方法可以帮助我们轻松实现序列化和反序列化这个库怎么使用呢?我来演示一下#include compile.hpp #include jsoncpp/json/json.h #includerun.hpp int main() { // Compile::my_compile(code); // //int nns_run::Run(code); Json::Value in_value; in_value[code]zhangsan; in_value[age]18; Json::StyledWriter writer; std::string outwriter.write(in_value); std::coutout; Json::Value out_value; Json::Reader read; read.parse(out,out_value); std::string codeout_value[code].asCString(); int ageout_value[age].asInt(); std::coutcode\nagestd::endl; return 0; }具体上是怎么使用的呢?首先我们需要定义出一个Json::value假设我们需要进行序列化,我们就将我们需要序列话的数据进行填写然后定义出一个 Json::StyledWriter 对象将我们的value值写入到字符串中读取的话就是类似的步骤,首先定义出一个value对象和一个Reader对象,调用相关的读函数将我们需要读的json字符串读取到我们的value中然后读取value中的数据合并代码(编译和运行--引入json库)#include jsoncpp/json/json.h #include run.hpp #include compile.hpp #include ../comm/util.hpp #include ../comm/Log.hpp using namespace LogMoudle; using namespace util; class com_run { public: com_run() { } ~com_run() { } public: static std::string StuToCode(int stu_code, const std::string file_name) { std::string out; switch (stu_code) { case 0: out 编译运行成功; break; case -1: out 代码为空; break; case -2: out 未知错误; break; case -3: FileUtil::ReadFile(file_name, out, true); break; case SIGABRT: out 内存超出限制; break; case SIGXCPU: out cpu运行时间超限; break; case SIGFPE: out 浮点数溢出; break; default: break; } return out; } // code // input // cpulimit // memlimit static void Start(const std::string in_json, std::string *out_json) { Json::Value in_value; Json::Reader read; read.parse(in_json, in_value); std::string code in_value[code].asCString(); std::string input in_value[input].asCString(); int cpulimit in_value[cpulimt].asInt(); int memlimit in_value[memlimt].asInt(); int stu_code 0; int run_code 0; std::string file_name; Json::Value out_value; if (code.size() 0) { // 代码为空 stu_code -1; goto END; } file_name FileUtil::MakeUniqueFileName(); if (!FileUtil::WriteFile(PathUtil::Src(file_name), code)) { stu_code -2; // 未知错误 goto END; } if (!Compile::my_compile(file_name)) { stu_code -3; // 编译错误 goto END; } run_code ns_run::Run(file_name, cpulimit, memlimit); if (run_code 0) { stu_code -2; goto END; } else if (run_code 0) { stu_code run_code; goto END; } else { stu_code 0; } END: out_value[stu] stu_code; out_value[reason] StuToCode(stu_code, file_name); if (stu_code 0) { std::string out_put; FileUtil::ReadFile(PathUtil::StdOut(file_name), out_put, true); out_value[output] out_put; std::string _stderror; FileUtil::ReadFile(PathUtil::StdError(file_name), _stderror, true); out_value[stderror] _stderror; } Json::StyledWriter writer; *out_jsonwriter.write(out_value); } };现在我们的代码完成了合并的工作现在我们就可以对传来的json串进行编译和运行了,但是我们每次工作都会生成许许多多的临时文件,我们需要在工作的收尾部分对这些产生的临时文件进行删除删除临时文件static void RvTempFile(const std::string file_name) { std::string SRCPathUtil::Src(file_name); if(FileUtil::IsFileExists(SRC)) { unlink(SRC.c_str()); } std::string STDERRORPathUtil::StdError(file_name); if(FileUtil::IsFileExists(STDERROR)) { unlink(STDERROR.c_str()); } std::string _compile_errorPathUtil::CompilerError(file_name); if(FileUtil::IsFileExists(_compile_error)) { unlink(_compile_error.c_str()); } std::string _exePathUtil::Exe(file_name); if(FileUtil::IsFileExists(_exe)) { unlink(_exe.c_str()); } std::string _stdinPathUtil::StdIn(file_name); if(FileUtil::IsFileExists(_stdin)) { unlink(_stdin.c_str()); } std::string _stdoutPathUtil::StdOut(file_name); if(FileUtil::IsFileExists(_stdout)) { unlink(_stdout.c_str()); } }现在我们的项目中的编译和运行的模块基本完成
延伸阅读

更多相关文章

2026/9/26 23:45:54

七、Vue组件

一、组件定义 你可以把“组件”想象成乐高积木。在 Vue 中,我们不再是一笔一划地写一整个大网页,而是把网页拆分成一个个独立、可复用的小积木(比如导航栏、按钮、文章列表),然后像搭积木一样把它们拼起来。 1. 组件定…

2026/9/28 0:20:41

大模型读懂文档了吗——多模态RAG的文档理解

摘要 文档理解是多模态RAG系统的"第一公里",这一步的质量决定整个系统的上限——垃圾进,垃圾出。本文从多维分类体系出发,梳理不同文档类型对模型感知、结构理解、语义推理三层能力的差异化挑战,结合半导体显示领域的典…

2026/10/6 10:39:20

继承(全)

目录 一. 继承的概念及定义 1.1 继承的概念 1.2 继承的机制 1.3 继承的定义 1.3.1 定义格式​编辑 1.3.2 继承父类成员访问方式的变化 1.4 继承类模板 二. 父类和子类对象赋值兼容转换 2.2 类型转换的特殊处理规则 2.3 应用实例 三. 继承中的作用域 3.1 隐藏规则 …

2026/10/6 17:14:30

Spring事务失效的7个坑与底层原理:从JDBC到分布式事务

1. 事务失效的七宗罪:我踩过的坑,你大概率也会踩先讲个真实事故。几年前我维护过一个电商订单系统,线上出了一个诡异的bug:用户支付成功后,订单状态正常更新,但库存却莫名其妙多扣了一次。代码看起来完全没…

2026/10/6 17:14:30

R+ggplot2复现NC风格分组小提琴图:从数据到出图

做科研图表复现这事,我一直觉得最忌讳的就是只盯着别人的图“照猫画虎”,不知道图层背后为什么要这么叠。Nature Communications 里那类分组小提琴图,乍看就是几个“胖葫芦”并排摆在一起,可真要自己动手从数据一步步画出来&#…

2026/10/6 17:14:30

锂电池保护IC工作原理与实战排障指南

1. 为什么一块锂电池敢直接接上5V充电器?——保护IC才是真正的“守门人”你拆开过任何一块标称3.7V的锂电池吗?比如旧手机电池、蓝牙耳机电芯、或者电动工具里的18650?大概率会看到一块指甲盖大小的黑色小芯片,焊在电池正极引出线…

2026/10/6 17:14:30

数据结构实战速查手册:从逻辑到代码的四层映射

简介:本资源是一份面向计算机专业学生与考研备考者的《数据结构》核心知识点精要总结,聚焦课程基础概念、逻辑与存储结构、典型运算及算法复杂度分析等高频考点。内容覆盖概论、线性表、栈与队列三大核心章节,系统梳理数据元素/数据项定义、A…

2026/10/6 17:14:30

HTML转EXE打包全攻略:从Electron到Tauri的开箱即用方案

做前端的、做产品的,甚至只是帮领导做点小工具的朋友,最近都在问我同一个问题:我手上有个HTML页面,怎么给客户、同事、老总一个能双击就打开的EXE?这需求说起来轻巧,但真落地全是坑——有人随手找了个网页打…

2026/10/6 17:09:29

Agent-Reach 实战:用 Python 打造命令行 AI Agent 工具

1. 从零认识 Agent-Reach:一个把 AI Agent 拉进命令行的工具第一次看到 Agent-Reach 这个名字,我下意识把它拆成了两半:Agent 和 Reach。Agent 是当下最热的 AI 智能体,Reach 是“触达、够得着”的意思。合起来,它想解…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/5 17:38:27

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 0:03:23

MR25H40CDF+STM32F031C6工业级高可靠数据存储方案

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的 PLC 控制柜里、在风电变流器的散热片背面、在矿井监测终端的金属外壳下,你经常能看到一块指甲盖大小的黑色芯片——它既不是 Flash,也不是…

2026/10/6 0:03:23

MRAM+STM32工业断电数据保全实战指南

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的PLC柜里、在野外无人值守的环境监测终端里、在高速运转的包装机控制板上,你经常能看到一块指甲盖大小的黑色芯片,旁边贴着“MR25H40CDF”丝…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑