Asio20-BeastServer

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;
}

posted @ 2025-12-24 23:13  大胖熊哈  阅读(6)  评论(0)    收藏  举报