Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Srs | 21,803 | 5 hours ago | 93 | September 16, 2022 | 217 | mit | C++ | |||
SRS is a simple, high-efficiency, real-time video server supporting RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH, and GB28181. | ||||||||||
Node Fetch | 8,301 | 219,668 | 25,410 | 12 days ago | 86 | July 31, 2022 | 183 | mit | JavaScript | |
A light-weight module that brings the Fetch API to Node.js | ||||||||||
Piping Server | 2,740 | 2 | 5 days ago | 106 | September 04, 2022 | 16 | mit | TypeScript | ||
Infinitely transfer between every device over pure HTTP with pipes or browsers | ||||||||||
Aleph | 2,472 | 521 | 14 days ago | 117 | February 21, 2019 | 18 | mit | Clojure | ||
Asynchronous communication for Clojure | ||||||||||
Cinatra | 1,553 | 10 hours ago | 74 | mit | C++ | |||||
modern c++(c++20), cross-platform, header-only, easy to use http framework | ||||||||||
Squbs | 1,381 | 6 | a year ago | 12 | January 18, 2021 | 69 | apache-2.0 | Scala | ||
Akka Streams & Akka HTTP for Large-Scale Production Deployments | ||||||||||
Embedio | 1,301 | 33 | 26 | 6 months ago | 153 | March 11, 2020 | 40 | other | C# | |
A tiny, cross-platform, module based web server for .NET | ||||||||||
Ustreamer | 1,255 | 10 days ago | 23 | gpl-3.0 | C | |||||
µStreamer - Lightweight and fast MJPEG-HTTP streamer | ||||||||||
Download | 1,147 | 43,052 | 1,568 | a year ago | 73 | April 02, 2020 | 56 | mit | JavaScript | |
Download and extract files | ||||||||||
Ulfius | 932 | 14 days ago | 9 | lgpl-2.1 | C | |||||
Web Framework to build REST APIs, Webservices or any HTTP endpoint in C language. Can stream large amount of data, integrate JSON data with Jansson, and create websocket services |
English | 中文
OS (Compiler Version) | Status |
---|---|
Ubuntu 22.04 (clang 14.0.0) | |
Ubuntu 22.04 (gcc 11.2.0) | |
macOS Monterey 12 (AppleClang 14.0.0.14000029) | |
Windows Server 2022 (MSVC 19.33.31630.0) |
cinatra是一个高性能易用的http框架,它是用modern c++(c++20)开发的,它的目标是提供一个快速开发的c++ http框架。它的主要特点如下:
cinatra目前支持了http1.1/1.0, ssl和websocket, 你可以用它轻易地开发一个http服务器,比如常见的数据库访问服务器、文件上传下载服务器、实时消息推送服务器,你也可以基于cinatra开发一个mqtt服务器。 cinatra是世界上性能最好的http服务器之一,性能测试详见性能测试
除此之外,cinatra 还提供了一个基于C++20 协程的http(https) client,包括普通get/post请求、文件上传下载和web socket、redirect、proxy等功能。
cinatra目前被很多公司在使用,在这里可以看到谁在用cinatra.
cinatra是header-only的,直接引用头文件既可。
#include "cinatra.hpp"
using namespace cinatra;
int main() {
int max_thread_num = std::thread::hardware_concurrency();
http_server server(max_thread_num);
server.listen("0.0.0.0", "8080");
server.set_http_handler<GET, POST>("/", [](request& req, response& res) {
res.set_status_and_content(status_type::ok, "hello world");
});
server.run();
return 0;
}
5行代码就可以实现一个简单http服务器了,用户不需要关注多少细节,直接写业务逻辑就行了。
#include "cinatra.hpp"
using namespace cinatra;
int main() {
http_server server(std::thread::hardware_concurrency());
server.listen("0.0.0.0", "8080");
server.set_http_handler<GET, POST>("/test", [](request& req, response& res) {
auto name = req.get_header_value("name");
if (name.empty()) {
res.set_status_and_content(status_type::bad_request, "no name");
return;
}
auto id = req.get_query_value("id");
if (id.empty()) {
res.set_status_and_content(status_type::bad_request);
return;
}
res.set_status_and_content(status_type::ok, "hello world");
});
server.run();
return 0;
}
#include "cinatra.hpp"
using namespace cinatra;
//日志切面
struct log_t
{
bool before(request& req, response& res) {
std::cout << "before log" << std::endl;
return true;
}
bool after(request& req, response& res) {
std::cout << "after log" << std::endl;
return true;
}
};
//校验的切面
struct check {
bool before(request& req, response& res) {
std::cout << "before check" << std::endl;
if (req.get_header_value("name").empty()) {
res.set_status_and_content(status_type::bad_request);
return false;
}
return true;
}
bool after(request& req, response& res) {
std::cout << "after check" << std::endl;
return true;
}
};
//将信息从中间件传输到处理程序
struct get_data {
bool before(request& req, response& res) {
req.set_aspect_data("hello", std::string("hello world"));
return true;
}
}
int main() {
http_server server(std::thread::hardware_concurrency());
server.listen("0.0.0.0", "8080");
server.set_http_handler<GET, POST>("/aspect", [](request& req, response& res) {
res.set_status_and_content(status_type::ok, "hello world");
}, check{}, log_t{});
server.set_http_handler<GET,POST>("/aspect/data", [](request& req, response& res) {
std::string hello = req.get_aspect_data<std::string>("hello");
res.set_status_and_content(status_type::ok, std::move(hello));
}, get_data{});
server.run();
return 0;
}
本例中有两个切面,一个校验http请求的切面,一个是日志切面,这个切面用户可以根据需求任意增加。本例会先检查http请求的合法性,如果不合法就会返回bad request,合法就会进入下一个切面,即日志切面,日志切面会打印出一个before表示进入业务逻辑之前的处理,业务逻辑完成之后会打印after表示业务逻辑结束之后的处理。
cinatra目前支持了multipart和octet-stream格式的上传。
#include <atomic>
#include "cinatra.hpp"
using namespace cinatra;
int main() {
http_server server(std::thread::hardware_concurrency());
server.listen("0.0.0.0", "8080");
//http upload(multipart)
server.set_http_handler<GET, POST>("/upload_multipart", [](request& req, response& res) {
assert(req.get_content_type() == content_type::multipart);
auto& files = req.get_upload_files();
for (auto& file : files) {
std::cout << file.get_file_path() << " " << file.get_file_size() << std::endl;
}
res.set_status_and_content(status_type::ok, "multipart finished");
});
server.run();
return 0;
}
短短几行代码就可以实现一个http文件上传的服务器了,包含了异常处理和错误处理。
#include <atomic>
#include "cinatra.hpp"
using namespace cinatra;
int main() {
http_server server(std::thread::hardware_concurrency());
server.listen("0.0.0.0", "8080");
//http upload(octet-stream)
server.set_http_handler<GET, POST>("/upload_octet_stream", [](request& req, response& res) {
assert(req.get_content_type() == content_type::octet_stream);
auto& files = req.get_upload_files();
for (auto& file : files) {
std::cout << file.get_file_path() << " " << file.get_file_size() << std::endl;
}
res.set_status_and_content(status_type::ok, "octet-stream finished");
});
server.run();
return 0;
}
cinatra提供下载功能非常简单,不需要编写代码,具体方法:
1. 启动cinatra server
2. 将要下载的文件放到http server同一级的www目录下即可。
3. 如何下载:如果你把test.txt放到www之后,那么直接通过http://127.0.0.1:8090/test.txt下载即可。
//chunked download
//cinatra will send you the file, if the file is big file(more than 5M) the file will be downloaded by chunked. support continues download
#include "cinatra.hpp"
using namespace cinatra;
int main() {
http_server server(std::thread::hardware_concurrency());
server.listen("0.0.0.0", "8080");
//web socket
server.set_http_handler<GET, POST>("/ws", [](request& req, response& res) {
assert(req.get_content_type() == content_type::websocket);
req.on(ws_open, [](request& req){
std::cout << "websocket start" << std::endl;
});
req.on(ws_message, [](request& req) {
auto part_data = req.get_part_data();
//echo
std::string str = std::string(part_data.data(), part_data.length());
req.get_conn<cinatra::NonSSL>()->send_ws_string(std::move(str));
std::cout << part_data.data() << std::endl;
});
req.on(ws_error, [](request& req) {
std::cout << "websocket pack error or network error" << std::endl;
});
});
server.run();
return 0;
}
本代码演示如何使用io_service_inplace,然后自己控制http server的运行线程以及循环。 使用 [http://[::1]:8080/close] (IPv6) 或者 [http://127.0.0.1:8080/close] (IPv4) 来关闭http server。
#include "cinatra.hpp"
using namespace cinatra;
int main() {
bool is_running = true;
http_server_<io_service_inplace> server;
server.listen("8080");
server.set_http_handler<GET, POST>("/", [](request& req, response& res) {
res.set_status_and_content(status_type::ok, "hello world");
});
server.set_http_handler<GET, POST>("/close", [&](request& req, response& res) {
res.set_status_and_content(status_type::ok, "will close");
is_running = false;
server.stop();
});
while(is_running)
server.poll_one();
return 0;
}
本代码演示如何使用RESTful路径参数。下面设置了两个RESTful API。第一个API当访问,比如访问这样的urlhttp://127.0.0.1:8080/numbers/1234/test/5678
时服务器可以获取到1234和5678这两个参数,第一个RESTful API的参数是(\d+)
是一个正则表达式表明只能参数只能为数字。获取第一个参数的代码是req.get_matches()[1]
。因为每一个req不同所以每一个匹配到的参数都放在request
结构体中。
同时还支持任意字符的RESTful API,也就是示例展示的第二种RESTful API"/string/{}/test/{}"
,其要获取到的参数同一用{}
语法即可。当访问http://127.0.0.1:8080/string/params_1/test/api_test
,浏览器会返回params_1
字符串。
#include "cinatra.hpp"
using namespace cinatra;
int main() {
int max_thread_num = std::thread::hardware_concurrency();
http_server server(max_thread_num);
server.listen("0.0.0.0", "8080");
server.set_http_handler<GET, POST>(
R"(/numbers/(\d+)/test/(\d+))", [](request &req, response &res) {
std::cout << " matches[1] is : " << req.get_matches()[1]
<< " matches[2] is: " << req.get_matches()[2] << std::endl;
res.set_status_and_content(status_type::ok, "hello world");
});
server.set_http_handler<GET, POST>(
"/string/{}/test/{}", [](request &req, response &res) {
res.set_status_and_content(status_type::ok, req.get_matches()[1]);
});
server.run();
return 0;
}
void test_sync_client() {
{
std::string uri = "http://www.baidu.com";
coro_http_client client{};
auto result = client.get(uri);
assert(!result.net_err);
print(result.resp_body);
result = client.post(uri, "hello", req_content_type::json);
print(result.resp_body);
}
{
coro_http_client client{};
std::string uri = "http://cn.bing.com";
auto result = client.get(uri);
assert(!result.net_err);
print(result.resp_body);
result = client.post(uri, "hello", req_content_type::json);
print(result.resp_body);
}
}
#ifdef CINATRA_ENABLE_SSL
void test_coro_http_client() {
using namespace cinatra;
coro_http_client client{};
client.init_ssl("../../include/cinatra", "server.crt");
auto data = client.get("https://www.bing.com");
std::cout << data.resp_body << "\n";
data = client.get("https://www.bing.com");
std::cout << data.resp_body << "\n";
}
#endif
async_simple::coro::Lazy<void> test_async_client() {
std::string uri = "http://www.baidu.com";
{
coro_http_client client{};
auto data = co_await client.async_get(uri);
print(data.status);
data = co_await client.async_get(uri);
print(data.status);
data = co_await client.async_post(uri, "hello", req_content_type::string);
print(data.status);
}
#ifdef CINATRA_ENABLE_SSL
std::string uri2 = "https://www.baidu.com";
std::string uri3 = "https://cn.bing.com";
coro_http_client client{};
client.init_ssl("../../include/cinatra", "server.crt");
data = co_await client.async_get(uri2);
print(data.status);
data = co_await client.async_get(uri3);
print(data.status);
#endif
}
async_simple::coro::Lazy<void> test_upload() {
std::string uri = "http://example.com/";
coro_http_client client{};
auto result = co_await client.async_upload(uri, "test", "yourfile.jpg");
print(result.status);
std::cout << "upload finished\n";
client.add_str_part("hello", "coro_http_client");
client.add_file_part("test", "yourfile.jpg");
result = co_await client.async_upload(uri);
print(result.status);
std::cout << "upload finished\n";
}
async_simple::coro::Lazy<void> test_download() {
coro_http_client client{};
std::string uri =
"http://www.httpwatch.com/httpgallery/chunked/chunkedimage.aspx";
std::string filename = "test.jpg";
std::error_code ec{};
std::filesystem::remove(filename, ec);
auto r = co_await client.async_download(uri, filename);
assert(!r.net_err);
assert(r.status == 200);
std::cout << "download finished\n";
}
async_simple::coro::Lazy<void> test_websocket() {
coro_http_client client{};
client.on_ws_close([](std::string_view reason) {
std::cout << "web socket close " << reason << std::endl;
});
client.on_ws_msg([](resp_data data) {
if (data.net_err) {
std::cout << data.net_err.message() << "\n";
return;
}
std::cout << data.resp_body << std::endl;
});
bool r = co_await client.async_ws_connect("ws://localhost:8090/ws");
if (!r) {
co_return;
}
auto result =
co_await client.async_send_ws("hello websocket"); // mask as default.
std::cout << result.status << "\n";
result = co_await client.async_send_ws("test again", /*need_mask = */ false);
std::cout << result.status << "\n";
result = co_await client.async_send_ws_close("ws close");
std::cout << result.status << "\n";
}
cinatra提供了一个高性能的http1.1 压测工具, 它是基于coro_http_client 实现的,内部通过多线程和协程实现了高效的压测,能够在单核或多核cpu上发送大量请求以此来测试服务器性能。
./cinatra_press_tool -t 4 -c 40 -d 30s http://127.0.0.1
上面的命令代表使用4个线程并且保持40个连接打开(协程)对网址http://127.0.0.1
进行30s的基准测试。
输出如下:
Running 30s test @ http://127.0.0.1
4 threads and 40 connections
Thread Status Avg Max Variation Stdev
Latency 4.12ms 8.15ms 3.367ms 1.835ms
462716 requests in 30.001s, 592.198250MB read, total: 462716, errors: 0
Requests/sec: 15423.86666667
Transfer/sec: 19.739390MB
-c, --connections total number of HTTP connections to keep open with
each thread handling N = connections/threads (int)
-d, --duration duration of the test, e.g. 2s, 2m, 2h (string [=15s])
-t, --threads total number of threads to use (int [=1])
-H, --headers HTTP headers to add to request, e.g. "User-Agent: coro_http_press"
add multiple http headers in a request need to be separated by ' && '
e.g. "User-Agent: coro_http_press && x-frame-options: SAMEORIGIN" (string [=])
-r, --readfix read fixed response (int [=0])
-?, --help print this message
这里有两个参数与wrk不同
-H
参数,它表示添加http头到http请求中,该参数不止可以添加一个http头还可以以&&
符号(4个字符)为分隔符来组装多个http头到http请求。
比如-H User-Agent: coro_http_press
就是添加一个http头,而-H User-Agent: coro_http_press && x-frame-options: SAMEORIGIN
则为添加User-Agent: coro_http_press
和x-frame-options: SAMEORIGIN
两个http头到http请求。添加三个以及多个http头的方法和上述方法相同。
-r
参数,它表示是否读固定长度的response,这个参数可以避免频繁的解析response优化性能,有些服务器对于相同的请求返回的长度可能不同,这种情况下不设置这个参数或者将它设置为0。
websocket的业务函数是会多次进入的,因此写业务逻辑的时候需要注意,推荐按照示例中的方式去做。
qq群:545605838