C++asio网络编程(21)beast网络库实现http服务器

📅 发布时间:2026/7/9 6:25:47 👁️ 浏览次数:
C++asio网络编程(21)beast网络库实现http服务器
简介前面的几篇文章已经介绍了如何使用asio搭建高并发的tcp服务器以及http服务器。但是纯手写http服务器太麻烦了有网络库beast已经帮我们实现了。这一期讲讲如何使用beast实现一个http服务器。连接类// asio1.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。//#includeiostream// 引入Boost.Asio库提供TCP/IP网络通信核心功能套接字、定时器、异步操作#includeboost/asio.hpp// 引入Boost.Beast库封装HTTP/WebSocket协议处理逻辑#includeboost/beast.hpp// 引入自定义的endpoint头文件包含client_end_point函数声明#includeendpoint.h// 简化命名空间将boost::asio::ip::tcp简写为tcpusingboost::asio::ip::tcp;// 简化Beast命名空间后续用beast代替boost::beastnamespacebeastboost::beast;// 简化Asio命名空间后续用asio代替boost::asionamespaceasioboost::asio;// 重复定义tcp别名不影响仅简化书写usingtcpasio::ip::tcp;// 程序入口函数intmain(){// 调用自定义的客户端端点函数具体逻辑在endpoint.h/cpp中client_end_point();// 控制台输出测试信息std::coutHello World!\n;}// 接收TCP连接的服务器核心函数// 参数acceptor-用于监听端口的TCP接收器socket-用于与客户端通信的套接字voidhttp_server(tcp::acceptoracceptor,tcp::socketsocket){// 异步接受客户端连接非阻塞不阻塞主线程acceptor.async_accept(socket,[](beast::error_code ec){// 回调函数连接接受完成后执行// ec是错误码空表示接受连接成功if(!ec){// 连接成功创建http_connection智能指针对象接管socket并启动请求处理std::make_sharedhttp_connection(std::move(socket))-start();}// 递归调用自身持续监听下一个客户端连接实现循环接受连接http_server(acceptor,socket);});}// 开始监听并处理对端客户端发送的HTTP请求voidstart(){// 第一步异步读取客户端的HTTP请求read_request();// 第二步启动超时检测防止请求处理卡住check_deadline();}// 异步读取客户端的HTTP请求voidread_request(){// 获取当前对象的智能指针防止异步回调时对象被销毁autoselfshared_from_this();// Beast提供的异步读取HTTP请求接口http::async_read(socket_,// 与客户端通信的套接字buffer_,// 存储请求数据的缓冲区request_,// 存储解析后的HTTP请求对象// 读取完成后的回调函数[self](beast::error_code ec,std::size_t bytes_transferred){// 忽略未使用的参数读取的字节数避免编译器警告boost::ignore_unused(bytes_transferred);// 读取无错误ec为空if(!ec){// 调用请求处理函数处理解析后的HTTP请求self-process_request();}});}// 检测请求处理是否超时通过定时器实现voidcheck_deadline(){// 获取当前对象的智能指针防止异步回调时对象被销毁autoselfshared_from_this();// 定时器异步等待超时后执行回调deadline.async_wait({// 定时器等待完成后的回调函数[self](beast::error_code ec){// 定时器无错误触发表示超时if(!ec){// 关闭套接字终止当前连接超时处理self-socket_.close(ec);}}});}// 处理解析后的HTTP请求区分请求方法GET/POST等生成对应响应voidprocess_request(){// 设置响应的HTTP版本与请求版本一致如HTTP/1.1response_.version(request_.version());// 设置响应为非长连接处理完请求后关闭连接response_.keep.alive(false);// 根据HTTP请求方法GET/POST等分支处理switch(request_.method()){// 处理GET请求casehttp::verb::get:// 设置响应状态码为200 OK请求成功response_.result(http::status::ok);// 设置响应头Server字段标识服务器软件为Beastresponse_.set(http::field::server,Beast);// 生成GET请求对应的响应体create_response();break;// 处理POST请求注此处语法有笔误原代码为::http_server::verb::post保留原写法case::http_server::verb::post:// 设置响应状态码为200 OKresponse_result(http::status::ok);// 设置响应头Server字段标识服务器软件为Beastresponse_.set(http::field::server,Beast);// 生成POST请求对应的响应体create_post_response();// 处理非法POST请求注原代码重复case保留原写法casehttp::verb::post:// 设置响应状态码为400 Bad Request请求错误response_result(http::status::bad_request);// 设置响应头Content-Type为纯文本注原代码为text/plasin保留原拼写错误response_set(http::field::server,text/plasin);// 构造错误响应体提示请求方法无效beast::ostream(response_.body())Invalid request-methodstd::string(request_.method_string()).;break;}// 发送构造好的HTTP响应给客户端write_response();}// 处理GET请求根据请求路径路由生成不同的响应体voidcreate_response(){// 处理路由/count统计请求数if(request_.target()/count){// 设置响应头Content-Type为HTML格式response_.set(http::field::content_type,text/html);// 构造HTML响应体显示当前请求计数beast::ostream(response_.body())html\nheadtitleRequest count/title/head\nbody\nh1Request count/h1\npThere have been my_program_state::request_count()// 获取全局请求计数 requests so far./p\n/body\n/html\n;}// 处理路由/time返回当前时间elseif(request_.target()/time){// 设置响应头Content-Type为HTML格式response_.set(http::field::content_type,text/html);// 构造HTML响应体显示当前时间戳beast::ostream(response_.body())html\nheadtitleCurrent time/title/head\nbody\nh1Current time/h1\npThe current time is my_program_state::now()// 获取当前时间戳 seconds since the epoch./p\n/body\n/html\n;}// 处理未知路由else{// 设置响应状态码为404 Not Found资源未找到response_.result(http::status::not_found);// 设置响应头Content-Type为纯文本response_.set(http::field::content_type,text/plain);// 构造错误响应体提示文件未找到beast::ostream(response_.body())File not found\r\n;}}// 处理POST请求根据请求路径路由生成不同的响应体voidcreate_post_response(){// 处理路由/email接收邮箱相关的POST数据if(request_.target()/email){// 获取POST请求的请求体数据autobodythis-request_.body();// 将请求体缓冲区转换为字符串autobody_strboost::beast::buffers_to_string(body.data());// 控制台打印接收到的POST请求体std::coutreceive body is body_strstd::endl;// 设置响应头Content-Type为JSON格式this-response_.set(http::field::content_type,text/json);// 解析POST请求体中的JSON数据Json::Value root;// 响应JSON对象Json::Reader reader;// JSON解析器Json::Value src_root;// 请求JSON对象// 解析请求体字符串为JSON对象boolparse_successreader.parse(body_str,src_root);// JSON解析失败if(!parse_success){// 控制台打印解析失败信息std::coutFailed to parse JSON data!std::endl;// 构造错误响应JSON错误码1001root[error]1001;// 将JSON对象转为字符串std::string jsonstrroot.toStyledString();// 将JSON字符串写入响应体beast::ostream(this-response_.body())jsonstr;return;}// JSON解析成功提取email字段autoemailsrc_root[email].asString();// 控制台打印提取到的邮箱地址std::coutemail is emailstd::endl;// 构造成功响应JSONroot[error]0;// 错误码0表示成功root[email]src_root[email];// 返回接收到的邮箱地址root[msg]recevie email post success;// 成功提示信息// 将JSON对象转为字符串std::string jsonstrroot.toStyledString();// 将JSON字符串写入响应体beast::ostream(this-response_.body())jsonstr;}// 处理未知POST路由else{// 设置响应状态码为404 Not Found资源未找到response_.result(http::status::not_found);// 设置响应头Content-Type为纯文本response_.set(http::field::content_type,text/plain);// 构造错误响应体提示文件未找到beast::ostream(response_.body())File not found\r\n;}}// 异步发送构造好的HTTP响应给客户端voidwrite_response(){// 获取当前对象的智能指针防止异步回调时对象被销毁autoselfshared_from_this();// 设置响应头Content-Length响应体字节数response_.content_length(response_.body().size());// Beast提供的异步写入HTTP响应接口http::async_write(socket_,// 与客户端通信的套接字response_,// 要发送的HTTP响应对象// 写入完成后的回调函数[self](beast::error_code ec,std::size_t){// 优雅关闭套接字的发送方向告知客户端数据已发送完毕self-shutdown(tcp::socket::shutdown_send,ec);// 取消超时定时器响应已发送无需再检测超时self-deadline.cancel();});}总结本文介绍了如何使用beast网络库实现http服务器