C++项目 -- 负载均衡OJ(一)compile_server

C++项目 – 负载均衡OJ(二)compile_server

文章目录

  • C++项目 -- 负载均衡OJ(二)compile_server
  • 一、compile_server设计
    • 1.总体服务流程
  • 二、compiler.hpp
  • 三、runner.hpp
  • 四、compile_run.hpp
  • 五、compile_server.cc
    • 5.1.编译功能调试:
    • 5.2.CompileAndRun功能调试
    • 5.3.熟悉cpp-httplib库
    • 5.4.将CompileAndRun服务打包成一个网络服务
    • 5.5.使用Postman测试网络请求服务


一、compile_server设计

1.总体服务流程

在这里插入图片描述

  • 远端代码提交上来后,形成一份临时文件用于编译;
  • fork出一个子进程,让子进程执行编译(使用程序替换的功能调用g++进行编译),如果编译通过,标准输出没有结果;如果编译出错,需要行程临时文件来保存出错的结果,方便返回给客户端;
  • 主进程继续接收代码;

二、compiler.hpp

  • 该hpp文件主要提供编译文件的方法;
  • Compiler中的Compile函数用于将源cpp文件进行编译,源文件保存在现在目录下的temp子目录,如1234.cpp,我们需要根据源文件生成可执行文件.exe,当编译错误时需要生成标准错误文件.stderr;
    在这里插入图片描述
    • Compile函数使用util.hppPathUtil类中的方法来获取源文件对应的可执行文件名和标准错误文件名;
    • Compile函数创建子进程,在子进程中使用程序替换接口execlp,调用g++对文件进行编译,并将错误信息重定向到临时的错误信息文件.stderr中;
    • execlp第一个参数是替换调用哪个程序,后面的参数才是如何调用;
    • 程序替换并不会影响进程的文件描述符,因此重定向stderr针对子进程替换运行的程序依然生效
    • 在编译之前,需要将标准错误文件重定向到我们定义的临时错误文件中保存下来;
    • 父进程用来判断最后是否编译成功,使用comm模块中的IsFileExists函数来进行判断;
#pragma once

#include "../Comm/util.hpp"

namespace ns_compiler
{
    using namespace ns_util;
    class Compiler
    {
        // 该类只提供方法
    public:
        Compiler()
        {
        }
        ~Compiler()
        {
        }

        static bool Compile(const string &file_name)
        {
            pid_t pid = fork();
            if (pid < 0)
            {
                return false;
            }
            else if (pid == 0)
            {
                // 子进程,负责调用g++编译器进行编译
                // 在编译之前,需要打开保存错误信息的临时文件,并将stderr重定向到该文件
                int _stderr = open(PathUtil::Stderr(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if(_stderr < 0)
                {
                    exit(0);
                }
                //重定向标准错误到_stderr
                dup2(_stderr, 2);

                //调用g++完成编译工作
                //g++ -o target src -std=c++11
                //最后一个参数后面一定要跟一个nullptr
                execlp("g++", "-o", PathUtil::Exe(file_name).c_str(),\
                    PathUtil::Src(file_name).c_str(), "-std=c++11", nullptr);
                //程序替换失败
                exit(2);
            }
            else
            {
                // 父进程
                waitpid(pid, nullptr, 0);
                //编译是否成功,看对应的文件夹下有没有生成对应的可执行程序
                if(FileUtil::IsFileExists(PathUtil::Exe(file_name)))
                {
                    return true;
                }
                return false;
            }
        }
    };
}

三、runner.hpp

  • runner.hpp文件主要用于编译成功的用户代码的运行功能的编写;
  • Run函数用于运行编译成功的用户代码生成的可执行程序;
    • 输入参数指明文件名即可,不需要带后缀和路径;输入参数还需要指定子进程的资源占用限制,方便出题者来指定该题的限制;
    • 返回值用于标定该程序的运行情况:
      返回值>0:程序异常,退出时收到了信号,返回值就是对应的信号编号;
      返回值==0:正常运行完毕的,结果保存到了对应的临时文件中;
      返回值<0,内部错误;
    • 该函数无需判断用户的可执行程序的运行结果正确与否,只需考虑是否正确运行完毕;
    • 在程序运行期间,我们需要将标准输入、标准输出、标准错误三个文件全部打开并重定向,以便读取输入数据、保存运行结果和运行时的错误信息;
    • 文件打开后,文件描述符是可以被子进程继承下去的
    • 由于我们替换的程序是在tmp文件夹里面的,因此在选择程序替换接口的时候,我们不能选择不带路径的接口(直接去环境变量列表里面查询),需要选择指定路径的接口
      在这里插入图片描述
    • 我们需要限制子进程运行用户程序所占用的系统资源,避免系统资源的过度占用,可以通过SetProcLimit接口设置;
    • 最后通过信号判断程序运行是否异常,如果没有异常,子进程的状态信息status返回0,如果有异常,一定返回大于0的值;
  • SetProcLimit函数用于设置进程占用的资源大小
    • 输入参数用来指定cpu运行时间和内存空间的占用限制,内存空间使用KB为单位;
    • 使用sertlimit接口来对进程的资源进行限制:
      在这里插入图片描述
    • resource是限制资源的类型:
      在这里插入图片描述
    • rlim是一个结构体,软限制为一般进程设置的限制,硬限制为我们所能设置的最大资源的上限值,一般设为无限制;
      在这里插入图片描述

四、compile_run.hpp

  • 该文件主要实现的功能是:
    • 适配用户需求,定制通信协议;
    • 正确调用compile and run;
    • 形成唯一文件名;
  • CompileAndRun类中的Start函数主要完成的功能有:
    • 接受客户端传来的序列化的字符串,并完成反序列化;
      在这里插入图片描述
    • 序列化工具使用jsoncpp库中的接口,
      在这里插入图片描述
      编译时需要链接库:
      在这里插入图片描述
      形成的是序列化的kv值的字符串:
      在这里插入图片描述
      json的作用:将结构化的数据转化成为一个字符串;
    • 在完成反序列化后,调用FileUtil类中的UniqueFileName方法生成唯一的代码源文件,然后调用WriteFile将代码写入该文件中;
    • reader.parse接口用于完成反序列化;asString是将json中的v作为字符串;
    • 形成用户代码源文件后,对其进行编译和运行操作,返回运行的信息;
    • 使用goto语句进行统一的差错处理,一旦上面的创建源文件、编译、运行出错,先赋值错误代码给status_code,然后goto到END处进行错误代码解析,并通过jsoncpp工具完成序列化;
    • goto语句之间不允许有任何的变量定义
    • 最后删除临时文件;
  • CodeToDesc函数主要完成返回错误代码对应的错误原因功能:
    在这里插入图片描述
    • RemoveTempFile函数主要完成清理临时文件的功能:
      使用unlink接口删除文件
      在这里插入图片描述

五、compile_server.cc

5.1.编译功能调试:

#include "compiler.hpp"

using namespace ns_compiler;

int main() 
{
    std::string file = "code";
    Compiler::Compile(file);

    return 0;
}

在现路径temp文件夹下创建code.cpp文件,测试编译功能:
在这里插入图片描述
在这里插入图片描述
编译运行compile_server.cc:
在这里插入图片描述
在这里插入图片描述
生成.exe和.stderr文件,此时.stderr文件是没有内容的;

  • 如果code.cpp中有错误:
    日志报错:
    在这里插入图片描述
    只会生成.stderr文件,里面保存报错信息:
    在这里插入图片描述

5.2.CompileAndRun功能调试

  • R"()"是c++11的raw string原生字符串,如果出现特殊字符,保持原貌
#include "compile_run.hpp"

using namespace ns_compiler;
using namespace ns_runner;
using namespace ns_compile_and_run;

int main() 
{
    //充当客户端请求的json串
    string in_json;
    Json::Value in_value;
    //c++11原生字符串:R"()"
    in_value["code"] = R"(#include<iostream>
    int main()
    {
        std::cout << "hello world" << std::endl;
        return 0;
    })";
    in_value["input"] = "";
    in_value["cpu_limit"] = 1;
    in_value["mem_limit"] = 10240 * 3;
    Json::FastWriter writer;
    in_json = writer.write(in_value);

    cout << in_json << endl;

    string out_json;
    CompileAndRun::Start(in_json, out_json);
    cout << out_json << endl;

    return 0;
}
  • 编译并运行成功;
    在这里插入图片描述成功在路径下生成文件名;
    在这里插入图片描述
  • 编译失败,得到失败原因
    在这里插入图片描述
  • CPU运行超时:
    在这里插入图片描述
  • 超出内存限制:
    在这里插入图片描述
  • 除0错误:
    在这里插入图片描述

5.3.熟悉cpp-httplib库

  • 接入cpp-httplib只需将httplib.h拷贝至项目中并包含,就可以使用;
  • cpp-httplib需使用高版本的gcc进行编译,最好在gcc 7以上;
  • cpp-httplib是阻塞式多线程的一个网络http库;
  • erver类中Get函数是接受请求并响应,第一个参数是根目录下的服务名称,第二个参数是响应的回调函数,用户访问更目录下的响应服务,服务器就会调用回调函数并返回响应;
  • Request是请求类,Responce是响应类;
  • content-type中text/explain是文本
  • 当用户请求hello服务时,就响应相应的文本
#include "compile_run.hpp"
#include "../Comm/httplib.h"

using namespace ns_compiler;
using namespace ns_runner;
using namespace ns_compile_and_run;
using namespace httplib;

int main() 
{
    Server svr;
    //用户如果请求根目录下的hello服务,服务器就会调用回调函数并返回响应
    svr.Get("/hello", [](const Request &req, Response &resp){
        //content-type中text/plain表示文本格式
        //编码格式设置为为utf-8
        resp.set_content("hello httplib!", "text/plain;charset=utf-8");
    });

    svr.listen("0.0.0.0", 8080);
    return 0;
}

在这里插入图片描述

  • 设置根目录与首页:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5.4.将CompileAndRun服务打包成一个网络服务

  • 用户使用Post进行请求CompileAndRun服务;
  • 用户的请求存在Request中的body;
  • 服务器给用户的响应是json格式的,因此content-type要设置成applocation/json;
  • 从命令行参数获取端口号;
#include "compile_run.hpp"
#include "../Comm/httplib.h"

using namespace ns_compiler;
using namespace ns_runner;
using namespace ns_compile_and_run;
using namespace httplib;

void Usage(const string proc)
{
    std::cerr << "Usage: " << "\n\t" << proc << "port" << endl;
}

int main(int argc, char *argv[]) 
{
    if(argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    Server svr;

    svr.Post("/compile_and_run", [](const Request &req, Response &resp){
        //用户请求的服务正文是我们想要的json string
        string in_json = req.body;
        string out_json;
        if(!in_json.empty())
        {
            CompileAndRun::Start(in_json, &out_json);
            resp.set_content(out_json, "application/json;charset=utf-8");
        }
    });

    svr.listen("0.0.0.0", atoi(argv[1]));
    
    return 0;
}
    return 0;
}

5.5.使用Postman测试网络请求服务

  • 设置Postman的请求为POST,请求的Body中内容为Row的Json格式,内容如下:
    在这里插入图片描述
  • 然后运行CompileServer服务,并建立向云服务器的8080号端口的请求:
    在这里插入图片描述
    在这里插入图片描述
  • Postman端收到了服务端返回的Json串,表明服务运行成功;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/474154.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【记录搭建elk 如何在linux共享文件】

『如何在linux共享文件 &#xff0c;搭建elk直接看第二部分』 新增用户a b c adduser a adduser b adduser c新增用户组 A groupadd developteam将用户a b c 加入 组 usermod -a -G developteam hadoop usermod -a -G developteam hbase usermod -a -G developteam hive设置um…

拷贝他人maven仓库jar包到自己本地仓库,加载maven依然提示无法下载对应依赖

所遇问题&#xff1a; 拷贝他人maven仓库jar包到自己本地maven仓库repository下的对应依赖位置&#xff0c;重新加载idea的maven依然提示无法下载对应依赖。 解决办法&#xff1a; 在maven->repository找到对应报错依赖路径&#xff0c;删除xxx.repositories 和 xxx.lastU…

蓝桥杯算法心得——附近最小(优先队列+滑动窗口)

大家好&#xff0c;我是晴天学长&#xff0c;这题可以用贪心优先队列和滑动窗口来写&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .附近最小 问题描述 小蓝有—个序列a[1], a[2],...,a[n]。 给定—个…

【MySQL】7. 基本查询(create / retrieve)

表的增查 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 1. Create 语法&#xff1a; INSERT [INTO] table_name[(column [, column] ...)] VALUES (value_list) [, (value_list)] ...value_list: value, […

【办公类-16-07-07】“2023下学期 大班户外游戏2(有场地和无场地版,每天不同场地)”(python 排班表系列)

作品展示 背景需求&#xff1a; 2024年2月教务组发放的是“每周五天内容相同&#xff0c;两周10天内容相同”的户外游戏安排 【办公类-16-07-05】合并版“2023下学期 大班户外游戏&#xff08;有场地和无场地版&#xff0c;两周一次&#xff09;”&#xff08;python 排班表系…

探秘国内ip切换手机软件,全是干货,火速Get!

随着互联网的普及和深入&#xff0c;人们在网络空间中的活动也变得越来越频繁。然而&#xff0c;在享受网络便利的同时&#xff0c;个人隐私保护和数据安全问题愈发突出。国内IP切换手机软件因其功能多样、易用性强大而备受关注。这类软件可以帮助用户切换IP地址&#xff0c;隐…

百度智能云+SpringBoot=AI对话【人工智能】

百度智能云SpringBootAI对话【人工智能】 前言版权推荐百度智能云SpringBootAI对话【人工智能】效果演示登录AI对话 项目结构后端开发pom和propertiessql_table和entitydao和mapperservice和implconfig和utilLoginController和ChatController 前端开发css和jslogin.html和chat.…

Java newInstance方法学习

用newInstance与用new是有区别的&#xff0c;区别在于创建对象的方式不一样&#xff0c;前者是使用类加载机制&#xff1b; newInstance方法要求该 Class 对应类有无参构造方法&#xff1b; 执行 newInstance()方法实际上就是使用对应类的无参构造方法来创建该类的实例&#x…

【prometheus-operator】k8s监控集群外redis

1、部署exporter GitHub - oliver006/redis_exporter: Prometheus Exporter for Redis Metrics. Supports Redis 2.x, 3.x, 4.x, 5.x, 6.x, and 7.x redis_exporter-v1.57.0.linux-386.tar.gz # 解压 tar -zxvf redis_exporter-v1.57.0.linux-386.tar.gz # 启动 nohup ./redi…

流畅的 Python 第二版(GPT 重译)(三)

第五章&#xff1a;数据类构建器 数据类就像孩子一样。它们作为一个起点是可以的&#xff0c;但要作为一个成熟的对象参与&#xff0c;它们需要承担一些责任。 马丁福勒和肯特贝克 Python 提供了几种构建简单类的方法&#xff0c;这些类只是一组字段&#xff0c;几乎没有额外功…

软件管理rpm与yum

源代码包下载 Compare, Download & Develop Open Source & Business Software - SourceForgehttps://sourceforge.net/ rpm包下载 Welcome to the RPM repository on fr2.rpmfind.nethttp://rpmfind.net/linux/RPM/ 软件包管理 1.rpm包管理: 1)查询: 安装…

蓝桥杯Python B组练习——完美的代价

一、题目 问题描述   回文串&#xff0c;是一种特殊的字符串&#xff0c;它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串&#xff0c;它不一定是回文的&#xff0c;请你计算最少的交换次数使得该串变成一个完美的回文串。   交换的定义是…

计算机网络相关

OSI七层模型 各层功能&#xff1a; TCP/IP四层模型 应用层 传输层 网络层 网络接口层 访问一个URL的全过程 在浏览器中输入指定网页的 URL。 浏览器通过 DNS 协议&#xff0c;获取域名对应的 IP 地址。 浏览器根据 IP 地址和端口号&#xff0c;向目标服务器发起一个 TCP…

电影aac是什么意思?如何播放、转换、编辑aac?

"电影AAC"这个术语可能是指电影中的音频编码格式。AAC&#xff08;Advanced Audio Coding&#xff09;是一种常见的音频编码格式&#xff0c;通常用于压缩音频文件&#xff0c;以在保持高质量的同时减小文件大小。在电影中&#xff0c;AAC格式的音频通常用于提供高质…

webpack5零基础入门-13生产模式

1.生产模式介绍 生产模式是开发完成代码后&#xff0c;我们需要得到代码将来部署上线。 这个模式下我们主要对代码进行优化&#xff0c;让其运行性能更好。 优化主要从两个角度出发: 优化代码运行性能优化代码打包速度 2.生产模式准备 我们分别准备两个配置文件来放不同的…

【RAG实践】基于 LlamaIndex 和Qwen1.5搭建基于本地知识库的问答机器人

什么是RAG LLM会产生误导性的 “幻觉”&#xff0c;依赖的信息可能过时&#xff0c;处理特定知识时效率不高&#xff0c;缺乏专业领域的深度洞察&#xff0c;同时在推理能力上也有所欠缺。 正是在这样的背景下&#xff0c;检索增强生成技术&#xff08;Retrieval-Augmented G…

PC 端 LVGL 模拟器之 Visual Studio

LVGL&#xff08;Light and Versatile Graphics Library&#xff09;是一个轻量化的、开源的、在嵌入式系统中广泛使用的图形库&#xff0c;它提供了一套丰富的控件和组件&#xff0c;只需要少量的内存和计算资源&#xff0c;使得在资源受限的设备上创建高端的图形界面成为可能…

pycorrector检测OCR错字实践

参考&#xff1a;https://github.com/shibing624/pycorrector/tree/master/examples/macbert stopwords.txt 添加专业停用词&#xff0c;避免错误 设置自定义词典&#xff0c;避免将正确的词错误检测成错误的词 from pycorrector import Corrector m Corrector() m.set_cus…

Mysql——基础命令集合

目录 前期准备 先登录数据库 一、管理数据库 1.数据表结构解析 2.常用数据类型 3.适用所有类型的修饰符 4.使用数值型的修饰符 二、SQL语句 1.SQL语言分类 三、Mysql——Create,Show,Describe,Drop 1.创建数据库 2.查看数据库 3.切换数据库 4.创建数据表 5.查看…

ELK快速搭建图文详细步骤

目录 一、下载地址二、安装docker-compose(已安装则跳过)三、初始化ELK1. 赋予/setup/entrypoint.sh执行权限2. 初始化 docker-elk 所需的 Elasticsearch 用户和组3. 重置默认用户的密码4. 替换配置文件中的用户名和密码5. 重启 Logstash 和 Kibana&#xff0c;使用新密码重新连…