Asio20-BeastServer
HttpApi
// 创建请求
http::request<http::string_body> req;
req.method(http::verb::get); // 设置方法: get, post, put, delete
req.target("/api/data"); // 设置目标路径
req.version(11); // HTTP 版本 (10=1.0, 11=1.1)
// 设置头部字段
req.set(http::field::host, "example.com");
req.set(http::field::user_agent, "My Client");
req.set(http::field::content_type, "application/json");
req.set(http::field::authorization, "Bearer token123");
// 设置消息体
req.body() = "Request body content";
req.prepare_payload(); // 自动计算 Content-Length
// 创建响应
http::response<http::string_body> res;
res.result(http::status::ok); // 状态码: ok, created, not_found, etc.
res.version(11);
res.keep_alive(true); // 保持连接
// 读取请求信息
std::string method = req.method_string();
std::string target = std::string(req.target());
std::string body = req.body();
bool keep_alive = req.keep_alive();
// 访问头部
if (req.find(http::field::content_type) != req.end()) {
std::string content_type = req[http::field::content_type].to_string();
}
// 缓冲区操作
beast::flat_buffer buffer;
std::string data = beast::buffers_to_string(buffer.data());
buffer.consume(buffer.size()); // 清空缓冲区
// 流操作
beast::tcp_stream stream(socket);
stream.expires_after(30s); // 设置超时
stream.expires_never(); // 禁用超时
// 错误处理
beast::error_code ec;
if (ec) {
std::cout << "Error: " << ec.message() << std::endl;
if (ec == beast::error::timeout) {
// 处理超时
}
}
websocket
// WebSocket 配置
ws_.set_option(websocket::stream_base::timeout::suggested(beast::role_type::server));
ws_.set_option(websocket::stream_base::decorator(callback));
// 消息类型
ws_.text(true); // 文本消息
ws_.binary(true); // 二进制消息
// 控制帧
ws_.ping(""); // 发送 ping
ws_.pong(""); // 发送 pong
ws_.close(code); // 关闭连接
// 读取消息属性
bool is_text = ws_.got_text();
bool is_binary = ws_.got_binary();
Http代码
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <chrono>
#include <ctime>
#include <fstream>
#include <iostream>
#include <json/json.h>
#include <json/reader.h>
#include <json/value.h>
#include <json/writer.h>
namespace bb {
std::size_t request_count()
{
static std::size_t count = 0;
return ++count;
}
std::time_t now()
{
return time(0);
}
}
class HttpConnection : public std::enable_shared_from_this<HttpConnection> {
public:
HttpConnection(boost::asio::ip::tcp::socket&& socket)
: _socket(std::move(socket))
{
}
void start()
{
read_request();
check_deadline();
}
private:
void read_request()
{
boost::beast::http::async_read(_socket, _buffer, _request, [this, self = shared_from_this()](const boost::system::error_code& ec, std::size_t bytes_transferred) {
boost::ignore_unused(bytes_transferred);
if (!ec) {
this->process_request();
}
});
}
void check_deadline()
{
_timer.async_wait([this, self = shared_from_this()](const boost::system::error_code& ec) {
if (!ec) {
this->_socket.close();
}
});
}
void process_request()
{
_response.version(_request.version());
_response.keep_alive(false);
switch (_request.method()) {
case boost::beast::http::verb::get:
_response.result(boost::beast::http::status::ok);
_response.set(boost::beast::http::field::server, "Beast");
create_get_response();
break;
case boost::beast::http::verb::post:
_response.result(boost::beast::http::status::ok);
_response.set(boost::beast::http::field::server, "Beast");
create_post_response();
break;
default:
_response.result(boost::beast::http::status::bad_request);
_response.set(boost::beast::http::field::content_type, "text/plain");
boost::beast::ostream(_response.body()) << "Invalid request-method '" << std::string(_request.method_string()) << "'";
break;
}
write_response();
}
void create_get_response()
{
if (_request.target() == "/count") {
_response.set(boost::beast::http::field::content_type, "text/html");
boost::beast::ostream(_response.body()) << "<html>\n"
<< "<head><title>Request Count</title></head>\n"
<< "<body>\n"
<< "<h1>Request Count</h1>\n"
<< "<p>This server has received " << bb::request_count() << " requests.</p>\n"
<< "</body>\n"
<< "</html>\n";
} else if (_request.target() == "/time") {
_response.set(boost::beast::http::field::content_type, "text/html");
boost::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 ";
{
std::time_t t = bb::now();
std::tm* tm_ptr = std::localtime(&t);
std::ostringstream oss;
oss << std::put_time(tm_ptr, "%Y-%m-%d %H:%M:%S");
boost::beast::ostream(_response.body()) << oss.str();
}
boost::beast::ostream(_response.body()) << "</p>\n"
<< "</body>\n"
<< "</html>\n";
} else if (_request.target() == "/fils") {
_response.set(boost::beast::http::field::content_type, "image/jpg");
std::ifstream file("/home/vivek/Pictures/Screenshots/250819_20h02m43s_screenshot.png", std::ios::binary);
if (file.is_open()) {
boost::beast::ostream(_response.body()) << file.rdbuf();
_response.prepare_payload();
file.close();
}
} else {
_response.result(boost::beast::http::status::not_found);
_response.set(boost::beast::http::field::content_type, "text/plain");
boost::beast::ostream(_response.body()) << "Resource not found\r\n";
}
}
void create_post_response()
{
if (_request.target() == "/email") {
auto& body = _request.body();
auto body_str = boost::beast::buffers_to_string(body.data());
std::cout << "Received email: " << body_str << std::endl;
_response.set(boost::beast::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: " << std::endl;
root["error"] = 1001;
std::string jsonstr = root.toStyledString();
boost::beast::ostream(_response.body()) << jsonstr;
return;
}
auto email = src_root["email"].asString();
std::cout << "Received email: " << email << std::endl;
root["error"] = 0;
root["email"] = src_root["email"];
std::string jsonstr = root.toStyledString();
boost::beast::ostream(_response.body()) << jsonstr;
} else {
_response.result(boost::beast::http::status::not_found);
_response.set(boost::beast::http::field::content_type, "text/plain");
boost::beast::ostream(_response.body()) << "Resource not found\t\n";
}
}
void write_response()
{
_response.content_length(_response.body().size());
boost::beast::http::async_write(_socket, _response, [this, self = shared_from_this()](const boost::system::error_code& ec, std::size_t bytes_transferred) {
boost::ignore_unused(bytes_transferred);
self->_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
self->_timer.cancel();
});
}
private:
boost::asio::ip::tcp::socket _socket;
boost::beast::flat_buffer _buffer { 8192 };
boost::beast::http::request<boost::beast::http::dynamic_body> _request;
boost::beast::http::response<boost::beast::http::dynamic_body> _response;
boost::asio::steady_timer _timer { _socket.get_executor(), std::chrono::seconds(10) };
};
void httpServer(boost::asio::ip::tcp::acceptor& acceptor)
{
auto socket = std::make_shared<boost::asio::ip::tcp::socket>(acceptor.get_executor());
acceptor.async_accept(*socket, [&, socket](const boost::system::error_code& ec) {
if (!ec) {
std::cout << "New connection" << std::endl;
std::cout << "Remote endpoint: " << socket->remote_endpoint().address().to_string() << ":" << socket->remote_endpoint().port() << std::endl;
std::make_shared<HttpConnection>(std::move(*socket))->start();
}
httpServer(acceptor);
});
}
int main()
{
try {
boost::asio::io_context io_context;
boost::asio::ip::tcp::acceptor acceptor(io_context, { boost::asio::ip::tcp::v4(), 8080 });
httpServer(acceptor);
io_context.run();
} catch (const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << std::endl;
}
return 0;
}