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