柚子快報(bào)邀請(qǐng)碼778899分享:運(yùn)維 負(fù)載均衡式在線(xiàn)OJ
柚子快報(bào)邀請(qǐng)碼778899分享:運(yùn)維 負(fù)載均衡式在線(xiàn)OJ
個(gè)人主頁(yè):Lei寶啊?
愿所有美好如期而遇
目錄
一、所用技術(shù)與開(kāi)發(fā)環(huán)境
所用技術(shù)
開(kāi)發(fā)環(huán)境
二、準(zhǔn)備及庫(kù)的安裝
1. 升級(jí)gcc? ?(gcc -v查看gcc版本, 超過(guò)7就不用看本條升級(jí)gcc)
2. 安裝 jsoncpp
3. 安裝 cpp-httplib?
4. 安裝boost庫(kù)
5. 安裝ctemplate
?三、項(xiàng)目宏觀結(jié)構(gòu)
1. leetcode結(jié)構(gòu)
2. 項(xiàng)目宏觀結(jié)構(gòu)
3. 編寫(xiě)思路
四、compiler服務(wù)設(shè)計(jì)
1. 日志模塊
2. 公共方法模塊
3. 編譯模塊
4. 運(yùn)行模塊
5. 整合模塊?
6. 主函數(shù)
7. 使用Postman進(jìn)行調(diào)試
五、oj_server服務(wù)設(shè)計(jì)
第一個(gè)功能:用戶(hù)請(qǐng)求的服務(wù)器路由功能
第二個(gè)功能:完成model,提供對(duì)數(shù)據(jù)的操作
第三個(gè)功能:control模塊,邏輯控制模塊
第四個(gè)功能:view模塊,進(jìn)行數(shù)據(jù)渲染
完成control模塊,加入負(fù)載均衡?
六、效果演示?
一、所用技術(shù)與開(kāi)發(fā)環(huán)境
所用技術(shù)
C++ STL 標(biāo)準(zhǔn)庫(kù)
Boost 準(zhǔn)標(biāo)準(zhǔn)庫(kù)(字符串切割)
cpp-httplib 第三方開(kāi)源網(wǎng)絡(luò)庫(kù)
ctemplate 第三方開(kāi)源前端網(wǎng)頁(yè)渲染庫(kù)
jsoncpp 第三方開(kāi)源序列化、反序列化庫(kù)
負(fù)載均衡設(shè)計(jì)
多進(jìn)程、多線(xiàn)程
開(kāi)發(fā)環(huán)境
ubuntu 5云服務(wù)器
vscode
二、準(zhǔn)備及庫(kù)的安裝
1. 升級(jí)gcc? ?(gcc -v查看gcc版本, 超過(guò)7就不用看本條升級(jí)gcc)
對(duì)于cpp-httplib庫(kù)來(lái)說(shuō),用老的編譯器,要么編譯不通過(guò),要么運(yùn)行報(bào)錯(cuò)。
安裝scl來(lái)升級(jí)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 (啟動(dòng),只在本會(huì)話(huà)有效)
如果想每次登陸的時(shí)候,都是較新的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庫(kù)
sudo apt update 更新軟件包
sudo apt install libboost-all-dev(博主是unbuntu)
5. 安裝ctemplate
這個(gè)資源可以在這里找:https://hub.fastgit.xyz/OlafvdSpek/ctemplate?
接著將資源放到服務(wù)器上,執(zhí)行如下命令
./autogen.sh
./configure
make //編譯
make install //安裝到系統(tǒng)中 如果報(bào)錯(cuò),加上sudo
?三、項(xiàng)目宏觀結(jié)構(gòu)
comm 模塊
compiler模塊
oj_server模塊
1. leetcode結(jié)構(gòu)
本項(xiàng)目只實(shí)現(xiàn)了leetcode的題目列表和刷題功能。
2. 項(xiàng)目宏觀結(jié)構(gòu)
B/S模式:瀏覽器-服務(wù)器(Browser-Server, B/S)模式
3. 編寫(xiě)思路
先寫(xiě)compiler服務(wù)器,接著寫(xiě)oj_server,最后是前端頁(yè)面設(shè)計(jì),直接copy。
四、compiler服務(wù)設(shè)計(jì)
1. 日志模塊
其他模塊都會(huì)引用這個(gè)模塊,這個(gè)模塊我們之前的文章有詳細(xì)代碼和講解,我們這里不多贅述,貼出鏈接:日志介紹及簡(jiǎn)單實(shí)現(xiàn)
2. 公共方法模塊
這個(gè)模塊可以先直接跳過(guò)不看,當(dāng)后面模塊用到這個(gè)模塊中的方法時(shí)返回來(lái)看。
這里介紹幾個(gè)函數(shù):gettimeofday獲取時(shí)間戳,stat獲取文件屬性(能獲取就能說(shuō)明文件存在,獲取不到就說(shuō)明文件不存在);C++11及以上版本,支持在atomic頭文件中,我們使用atomic_int類(lèi)型定義的變量,有原子加、原子減、原子比較并交換、原子自增、原子自減等操作。
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
namespace ns_commfunc
{
const string temp = "./temp/";
// 將文件名變?yōu)槲募窂剑⑶姨砑雍缶Y
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");
}
//運(yùn)行模塊
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 = "運(yùn)行正常";
break;
case -1:
ret = "代碼為空";
break;
case -2:
ret = "未知錯(cuò)誤";
break;
case -3:
// ret = "編譯錯(cuò)誤";
FileUtil::Readfile(filename, ret, true);
break;
case 24:
ret = "超時(shí)";
default:
ret = "待填充";
break;
}
return ret;
}
};
}
3. 編譯模塊
1. 創(chuàng)建編譯類(lèi)Compile,封裝在命名空間ns_compile中:
namespace ns_compile
{
class Compile
{
private:
public:
Compile()
{}
~Compile()
{}
};
}
2. 寫(xiě)一個(gè)方法,完成編譯功能,那么這個(gè)方法的參數(shù)和返回值我們?nèi)绾卧O(shè)置?我們要明白,外面有一個(gè)整合模塊來(lái)接收請(qǐng)求,并且從請(qǐng)求中提取代碼并解析成字符串形成源文件,也就是說(shuō),我們的編譯方法,參數(shù)為這個(gè)文件名,也就是字符串類(lèi)型。返回值可以設(shè)置為bool類(lèi)型,表示是否編譯成功。
/*
@return val: 編譯結(jié)果是否成功
@pragma : 文件名
*/
static bool compile(const string& filename)
{}
接下來(lái)就可以創(chuàng)建子進(jìn)程,按照我們上面的邏輯寫(xiě)代碼了:
其中,我們?cè)赾omm文件夾下,創(chuàng)建了一個(gè)公共方法文件,這個(gè)文件中我們寫(xiě)不同模塊需要使用的公共方法,這些方法封在ns_commfunc中的不同類(lèi)中,有Path類(lèi),這個(gè)類(lèi)中的方法用來(lái)形成文件路徑;文件類(lèi),這個(gè)類(lèi)中的方法用來(lái)對(duì)文件進(jìn)行操作。
static bool compile(const string& filename)
{
int id = fork();
if(id < 0)
{
Log(ERROR, "子進(jìn)程創(chuàng)建失敗");
return false;
}
else if(id == 0)
{
//子進(jìn)程
//重定向
umask(0);
i
柚子快報(bào)邀請(qǐng)碼778899分享:運(yùn)維 負(fù)載均衡式在線(xiàn)OJ
文章來(lái)源
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。