目录
引入cpp-httplib库
对于后端编译与运行模块基本已经设计完成,最后用户是通过网络传递代码等信息;我们就要将这个模块引入网络服务,对于套接字的编写过程非常麻烦我们可以使用现成HTTP协议库。
cpp-httplib 是一个轻量级的、高效的C++ HTTP/HTTPS 客户端和服务器库。它由 Hideaki Sone(yhirose)开发,并在 MIT 许可下发布。该项目的主要目标是提供一种简单易用的方式,在 C++ 应用程序中实现 HTTP 和 HTTPS 功能。
任何版本都可以从网上下载得到,这个库是一个单头文件库,可以直接将这个库头文件下载转移到我们的项目公共模块中,使用时添加库头文件和打开命名空间即可。对于使用这个现成的HTTP库时我们的gcc编译器一定要高版本的至少要7版本以上,否则使用低版本的编译器时对于这个库可以会在编译或者运行时报错;因此我们需要对gcc编译器进行升级。这里大家从网上自行搜索升级,这里不过多哔哔。
将编译与运行服务打包
通过HTTP协议服务端收到请求,请求中的请求参数包含代码、输入、时间和空间限制信息,直接提取请求中的响应数据交给编译和运行模块即可;处理完代码后,将运行信息作为响应正文交给客户端即可。
代码
#include "compile_run.hpp"
#include <jsoncpp/json/json.h>
#include "../comm/httplib.h"
using namespace ns_compiler_and_run;
using namespace httplib;
// 编译服务随时可能被多个人请求,必须保证传递上来的代码,形成源文件名称的时候要具有唯一性,要不然多个用户之间会影响
//
void Usage(std::string proc)
{
std::cerr << "Usage : " << "\n\t" << proc << std::endl;
}
int main(int argc, char *argv[2])
{
if (argc != 2)
{
Usage(argv[0]);
return 1;
}
// 对外提供一个服务
Server svr;
svr.Post("/compile_and_run", [](const Request &req, Response &resp)
{
//用户请求的正文就是我们想要的 json string
std::string in_json = req.body;
std::string out_json;
if(!in_json.empty())
{
//不为空调用编译和运行服务
CompilerAndRun::Start(in_json,&out_json);
resp.set_content(out_json,"application/json;charset=utf-8");
} });
svr.listen("0.0.0.0", atoi(argv[1])); // //http
return 0;
}
客户端用户路由功能
编译与运行后端功能模块编写完成后,就要对前端模块进行设计;对于前端的设计简单来说就是建立一个小型网站,用户进入网站就是获取题目列表、编辑代码、提交判题,这三个主要的模块。
采用MVC结构进行设计
M: Model,通常是和数据交互的模块,比如,对题库进行增删改查(文件版,MySQL)
V: view, 通常是拿到数据之后,要进行构建网页,渲染网页内容,展示给用户的(浏览器)
C: control, 控制器,就是我们的核心业务逻辑
用户路由功能
根据用户的需求提供不同的服务,但是也就是只有三个功能:
- 获取题目列表
- 用户要根据题目编号,获取题目内容
- 提交代码,使用我们的判题功能(1,每道题的测试用例,2.compile_and_run功能)
路由功能代码
#include<iostream>
#include"../comm/httplib.h"
using namespace httplib;
int main()
{
//用户请求的路由功能
//根据用户的需求提供不同的服务
//获取题目列表
//用户要根据题目编号,获取题目内容
//提交代码,使用我们的判题功能(1,每道题的测试用例,2.compile_and_run功能)
Server svr;
svr.Get("/all_question",[](const Request &req,Response &resp){
resp.set_content("这是所有的题目列表","text/plain;charset=utf-8");
});
//
svr.Get(R"("/questions/(\d+))",[](const Request &req,Response &resp){
//题目编号
std::string number = req.matches[1];
resp.set_content("这是指定的一道题: "+number , "text/plain;charset=utf-8");
});
//正则表达式
//保证保持原始字符串
svr.Get(R"(/judge/(\d+))",[](const Request &req,Response &resp){
std::string number = req.matches[1];
resp.set_content("指定题目的判题: "+number,"text/plain;charset=utf-8");
});
svr.listen("0.0.0.0",8080);
return 0;
}
-
正则表达式(regex): 正则表达式是一种用于匹配字符串中字符组合的模式。它们提供了一种灵活的方式来搜索、匹配和操作文本。在这个代码中,正则表达式被用于匹配请求的URL路径中特定的模式。
-
R前缀: 在C++中,R前缀用于创建原始字符串字面量。原始字符串字面量将反斜杠(\)视为字面字符而不是转义字符。这在处理正则表达式或任何其他字符串时非常有用,你不想解释转义序列时可以使用它。
解释:
- 在第二和第三个路由定义中,正则表达式被用在原始字符串字面量(前缀为
R
)中,用于定义动态路由,匹配包含数字模式的URL。 - 在第二个路由(
/questions/(\d+)
)中,模式是寻找包含/questions/
后跟一个或多个数字的URL。括号(\d+)
捕获数字作为一个组,以备后用。 - 在第三个路由(
/judge/(\d+)
)中,模式类似,但匹配包含/judge/
后跟一个或多个数字的URL。 - 在与每个路由关联的lambda函数内部,从URL中捕获的数字使用
req.matches[1]
进行检索,其中req.matches
保存了正则表达式捕获的匹配组。然后使用这些数字来提供特定路由的响应。
今天对项目网络库引入和用户路由功能的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!