最近项目中要搭建自己的响应服务器,C++技术,能跟客户端通讯做一些功能,比如上传下载文件(文本的和二进制的,比如配置文件和应用程序的升级),比如用户登录、添加、修改等操作。
自己写规约做了一个,发现很麻烦,用二进制的方法,发送端、接收端的封包操作十分繁琐。
周末找到了cpp-httplib,又同时发现了nlohmann/json,发现用这两个库结合起来,就能用C++做一个类似Apache+PHP的网站服务器了!
代码编写十分简单,我这里举例的是根据库里的例子修改的,客户端是根据文档编写的,测试通过的。
需要说明的是虽说是http库,其实把cpp/h文件合二为一了,json.hpp就很说明问题,只不过httplib.h没有用hpp后缀,这个我们就不计较了,毕竟库很优秀!另外:库是多线程的,文档里有介绍,所以可以应对大部分用于客户端连接服务器升级文件获取配置等情况了。
对于能在服务器使用Apache或tomcat的,就不要用这个技术了,毕竟不如web技术来得简单。这个技术主要用于解决不打算在服务器配置这么复杂的web服务的情况。
还要说明的是:虽然文档里说gcc4.8以上就可以编译,但是编译后无法运行,gcc版本最低要到4.9.0,否则运行时提示正则的错误:
terminate called after throwing an instance of ‘std::regex_error’
what(): regex_error
已放弃 (core dumped)
分为客户端、服务器端,文档见如下链接:
https://gitee.com/iqxg/cpp-httplib/tree/master#post-with-multipart-form-data
客户端代码如下:
#include "inc/httplib.h"
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main(int argc, char const *argv[])
{
httplib::Client cli("http://localhost:1234");
ifstream fin("D:/1.jpg", ios::binary);
ostringstream os;
os << fin.rdbuf();
std::string content = os.str();
cout << content.length() << endl;
fin.close();
httplib::MultipartFormDataItems items = {
{"file", content, "1.jpg", "application/octet-stream"},
};
auto res = cli.Post("/post", items);
cout << res->body;
return 0;
}
服务器端代码如下:
//
// upload.cc
//
// Copyright (c) 2019 Yuji Hirose. All rights reserved.
// MIT License
//
#include <iostream>
#include <fstream>
#include "inc/httplib.h"
#include "inc/nlohmann/json.hpp"
using namespace httplib;
using namespace std;
using json = nlohmann::json;
const char *html = R"(
<form id="formElem">
<input type="file" name="file" accept="image/*">
<input type="submit">
</form>
<script>
formElem.onsubmit = async (e) => {
e.preventDefault();
let res = await fetch('/post', {
method: 'POST',
body: new FormData(formElem)
});
console.log(await res.text());
};
</script>
)";
int main(void)
{
Server svr;
svr.Get("/", [](const Request & /*req*/, Response &res)
{ res.set_content(html, "text/html"); });
svr.Post("/post", [](const Request &req, Response &res)
{
auto image_file = req.get_file_value("file");
cout << "image file length: " << image_file.content.length() << endl
<< "image file name: " << image_file.filename << endl;
{
ofstream ofs(image_file.filename, ios::binary);
ofs << image_file.content;
}
json result{
{"code", 0},
{"msg", "ok"},
{"data", image_file.content.length()}};
res.set_content(result.dump(), "text/plain");
});
svr.listen("localhost", 1234);
}
服务器端我保留了发送HTML的那段,毕竟既然是HTTP服务器,用浏览器访问也是一样的。
注意,windows里用命令行编译用:g++ server.cpp -lws2_32 -o server,否则会报 undefined reference to `__imp_setsockopt’等跟__imp_系列的socket类错误。
json的用法见https://www.cnblogs.com/maizhongfei/p/14164895.html