负载均衡式在线OJ

embedded/2024/12/23 8:41:46/

个人主页:Lei宝啊 

愿所有美好如期而遇


目录

一、所用技术与开发环境

所用技术

开发环境

二、准备及库的安装

1. 升级gcc   (gcc -v查看gcc版本, 超过7就不用看本条升级gcc)

2. 安装 jsoncpp

3. 安装 cpp-httplib 

4. 安装boost库

5. 安装ctemplate

 三、项目宏观结构

1. leetcode结构

2. 项目宏观结构

3. 编写思路

四、compiler服务设计

1. 日志模块

2. 公共方法模块

3. 编译模块

4. 运行模块

5. 整合模块 

6. 主函数

7. 使用Postman进行调试

五、oj_server服务设计

第一个功能:用户请求的服务器路由功能

第二个功能:完成model,提供对数据的操作

第三个功能:control模块,逻辑控制模块

第四个功能:view模块,进行数据渲染

完成control模块,加入负载均衡 

六、效果演示 


一、所用技术与开发环境

所用技术

  • 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

 三、项目宏观结构

  1. comm 模块
  2. compiler模块
  3. 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

http://www.ppmy.cn/embedded/109669.html

相关文章

P2P应用

当谈论P2P&#xff08;点对点&#xff09;应用程序时&#xff0c;我们实际上是在讨论一种网络架构和通信模式&#xff0c;它允许设备&#xff08;或节点&#xff09;直接连接并共享资源&#xff0c;而无需传统的客户端-服务器模型。P2P应用程序在许多领域都有广泛的应用&#x…

教师节重磅福利!《动手学强化学习》作者亲自带你学强化学习

作为大模型的核心技术之一&#xff0c;强化学习越来越受到人们的重视。强化学习&#xff08;Reinforcement Learning, RL&#xff09;是机器学习的一个领域&#xff0c;主要研究智能主体&#xff08;agent&#xff09;在环境中应该怎样采取行动以最大化所获得的累积奖励。目前强…

mysql——关于表的增删改查(CRUD)

目录 比较运算符和逻辑运算符图 一、增加&#xff08;Create&#xff09; 1、全列插入 2、指定列插入 二、查询&#xff08;Retrieve&#xff09; 1、全列查询 2、指定列查询 3、别名&#xff08;as&#xff09; 4、表达式查询 5、去重&#xff08;distinct&#xff09; 6、…

时尚购物体验:Spring Boot技术在网页时装购物中的应用

第2章相关技术 2.1 B/S架构 B/S结构的特点也非常多&#xff0c;例如在很多浏览器中都可以做出信号请求。并且可以适当的减轻用户的工作量&#xff0c;通过对客户端安装或者是配置少量的运行软件就能够逐步减少用户的工作量&#xff0c;这些功能的操作主要是由服务器来进行控制的…

IP查询技术:构建网络安全的坚实防线

在数字化时代&#xff0c;企业网络面临着复杂多变的威胁与挑战。因此&#xff0c;构建一个稳固的网络安全体系至关重要。而IP查询技术&#xff0c;作为网络安全防御体系中的一把利剑&#xff0c;正日益成为企业防范网络风险的重要工具。 什么是IP查询技术&#xff1f; IP查询…

Redis缓存常用的读写策略

缓存常用的读写策略 缓存与DB的数据不一致问题&#xff0c;大多数都是指DB的数据已经修改&#xff0c;而缓存中的数据还是旧数据的情况。 旁路缓存模式 对于读操作&#xff1a;基本上所有模式都是先尝试从缓存中读&#xff0c;没有的话再去DB读取&#xff0c;然后写到缓存中…

Python重试库对比:选择最适合你的重试工具(自定义重试装饰器)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒🎯 安装方法📝 `retrying` 库📝 `tenacity` 库📝 `backoff` 库📝 `retry` 库📝 选择推荐📝 自定义重试函数实现🎈 参数说明🎈 解析与优化⚓️ 相关链接 ⚓️📖 介绍 📖 曾经有这样一个场景,…

【QT】十分钟全面理解 信号与槽的机制

目录 从一个定时器开始全方位简介1. 基本的信号与槽连接语法例子 2. 使用函数指针连接信号与槽&#xff08;现代 C 风格&#xff09;语法例子 3. 使用 Lambda 表达式作为槽语法例子 4. 自动连接&#xff08;QMetaObject::connectSlotsByName&#xff09;规则例子 5. 信号与槽的…