beast网络库搭建http服务器

发布时间 2023-08-14 19:19:26作者: 白伟碧一些小心得

参考:https://llfc.club/category?catid=225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2RlhDCg4eedYme46C6ddo4cKcFN

简介

前面的几篇文章已经介绍了如何使用asio搭建高并发的tcp服务器,以及http服务器。但是纯手写http服务器太麻烦了,有网络库beast已经帮我们实现了。这一期讲讲如何使用beast实现一个http服务器。

连接类

我们先实现http_server函数

  1. void http_server(tcp::acceptor& acceptor, tcp::socket& socket)
    {
    acceptor.async_accept(socket,
    [&](beast::error_code ec)
    {
    if (!ec)
    std::make_shared<http_connection>(std::move(socket))->start();
    http_server(acceptor, socket);
    });
    }

     

http_server中添加了异步接收连接的逻辑,当有新的连接到来时创建http_connection,然后启动服务,新连接监听对端数据。接下来http_server继续监听对端的新连接。
连接类http_connection里实现了start函数监听对端数据

  1. void start()
    {
    read_request();
    check_deadline();
    }

     

处理读请求,将读到的数据存储再成员变量request_中,然后调用process_request处理请求

 

void read_request()
{
auto self = shared_from_this();
http::async_read(
socket_,
buffer_,
request_,
[self](beast::error_code ec,
std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if (!ec)
self->process_request();
});
}

 

check_deadline主要时用来检测超时,当超过一定时间后自动关闭连接,因为http请求时短链接

 

void
check_deadline()
{
auto self = shared_from_this();
deadline_.async_wait(
[self](beast::error_code ec)
{
if (!ec)
{
// Close socket to cancel any outstanding operation.
self->socket_.close(ec);
}
});
}

 

process_request函数中区分请求的类型,进行不同类型的处理如post还是get请求

 

void process_request()
{
response_.version(request_.version());
response_.keep_alive(false);
switch (request_.method())
{
case http::verb::get:
response_.result(http::status::ok);
response_.set(http::field::server, "Beast");
create_response();
break;
case http::verb::post:
response_.result(http::status::ok);
response_.set(http::field::server, "Beast");
create_post_response();
break;
default:
// We return responses indicating an error if
// we do not recognize the request method.
response_.result(http::status::bad_request);
response_.set(http::field::content_type, "text/plain");
beast::ostream(response_.body())
<< "Invalid request-method '"
<< std::string(request_.method_string())
<< "'";
break;
}
write_response();
}

 

create_response函数中解析了不同的路由处理get请求

 

void
create_response()
{
if (request_.target() == "/count")
{
response_.set(http::field::content_type, "text/html");
beast::ostream(response_.body())
<< "<html>\n"
<< "<head><title>Request count</title></head>\n"
<< "<body>\n"
<< "<h1>Request count</h1>\n"
<< "<p>There have been "
<< my_program_state::request_count()
<< " requests so far.</p>\n"
<< "</body>\n"
<< "</html>\n";
}
else if (request_.target() == "/time")
{
response_.set(http::field::content_type, "text/html");
beast::ostream(response_.body())
<< "<html>\n"
<< "<head><title>Current time</title></head>\n"
<< "<body>\n"
<< "<h1>Current time</h1>\n"
<< "<p>The current time is "
<< my_program_state::now()
<< " seconds since the epoch.</p>\n"
<< "</body>\n"
<< "</html>\n";
}
else
{
response_.result(http::status::not_found);
response_.set(http::field::content_type, "text/plain");
beast::ostream(response_.body()) << "File not found\r\n";
}
}

 

create_post_response处理了post请求中的一部分路由

 

void create_post_response() {
if (request_.target() == "/email")
{
auto& body = this->request_.body();
auto body_str = boost::beast::buffers_to_string(body.data());
std::cout << "receive body is " << body_str << std::endl;
this->response_.set(http::field::content_type, "text/json");
Json::Value root;
Json::Reader reader;
Json::Value src_root;
bool parse_success = reader.parse(body_str, src_root);
if (!parse_success) {
std::cout << "Failed to parse JSON data!" << std::endl;
root["error"] = 1001;
std::string jsonstr = root.toStyledString();
beast::ostream(this->response_.body()) << jsonstr;
return ;
}
auto email = src_root["email"].asString();
std::cout << "email is " << email << std::endl;
root["error"] = 0;
root["email"] = src_root["email"];
root["msg"] = "recevie email post success";
std::string jsonstr = root.toStyledString();
beast::ostream(this->response_.body()) << jsonstr;
}
else
{
response_.result(http::status::not_found);
response_.set(http::field::content_type, "text/plain");
beast::ostream(response_.body()) << "File not found\r\n";
}
}

write_response发送请求

void write_response()
{
auto self = shared_from_this();
response_.content_length(response_.body().size());
http::async_write(
socket_,
response_,
[self](beast::error_code ec, std::size_t)
{
self->socket_.shutdown(tcp::socket::shutdown_send, ec);
self->deadline_.cancel();
});
}