文章目录 1、简介2、echo模式应答异步服务器2.1、Session会话类2.2、Server类为服务器接收连接的管理类 3、客户端4、隐患5、总结 1、简介 前文已经介绍了异
前文已经介绍了异步操作的api,今天写一个简单的异步echo服务器,以应答为主。
Session类主要是处理客户端消息接收发送的会话类,为了简单起见,我们不考虑粘包问题,也不考虑支持手动调用发送的接口,只以应答的方式发送和接收固定长度 (1024字节长度) 的数据。
“session.h” :
#pragma once#include #include #include class Session{public:Session(boost::asio::io_context& ioc);public:boost::asio::ip::tcp::Socket& GetSocket();void Start();protected://接收数据回调 tcp接收缓冲区有数据void HandlerRead(const boost::system::error_code& err, size_t bytes_transferred);//发送数据回调 tcp发送缓冲区有空闲空间,就会从用户缓冲区拷贝到tcp发送缓冲区,然后发送数据void HandleSend(const boost::system::error_code& err);protected:enum {max_length = 1024};//数组接收数据char data_[max_length];private:boost::asio::ip::tcp::socket socket_;};
这段代码是一个使用Boost.Asio库实现的 C++ 类定义,用于网络通信会话。您解释这段代码:
#pragma once#include #include #include
class Session{public: Session(boost::asio::io_context& ioc);public: boost::asio::ip::tcp::socket& GetSocket(); void Start();protected: // ...private: // ...};
公共成员函数:
Session(boost::asio::io_context& ioc):这是 Session 类的构造函数。它接受一个 io_context 的引用作为参数,通常用于管理异步I/O操作。
boost::asio::ip::tcp::socket& GetSocket():此函数返回一个TCP套接字对象的引用。它可能允许外部代码访问与此会话相关联的套接字。
void Start(): 此函数预计启动会话。代码片段没有提供其实际实现,但它可能启动一些用于网络通信的异步操作。
受保护的成员函数:
这些是受保护的成员函数。它们可能被派生类覆盖或在内部用于处理读取和发送操作。
HandlerRead(const boost::system::error_code& err, size_t bytes_transferred): 这个函数似乎是用于处理通过TCP连接接收的数据的回调。它接受错误代码和传输的字节数作为参数。
HandleSend(const boost::system::error_code& err): 这个函数似乎是用于处理发送数据完成的回调。它也接受一个错误代码作为参数。
protected: void HandlerRead(const boost::system::error_code& err, size_t bytes_transferred); void HandleSend(const boost::system::error_code& err);
private: boost::asio::ip::tcp::socket socket_;
这个私有成员变量 socket_ 是TCP套接字的实例,用于会话内的网络通信。
enum { max_length = 1024};
这定义了一个名为 max_length 的常量,其值为1024。这很可能是用于接收数据的缓冲区的最大长度。
总的来说,这段代码是一个使用Boost.Asio库的网络会话类的基本轮廓。它提供了管理网络通信所需的结构和组件,但没有在此片段中提供会话行为的实际实现。
“session.cpp” :
#include "Session.h"Session::Session(boost::asio::io_context& io_context):socket_(io_context){memset(data_, 0, sizeof(data_));}boost::asio::ip::tcp::socket& Session::GetSocket() {return socket_;}void Session::Start() {memset(data_, 0, max_length);socket_.async_read_some(boost::asio::buffer(data_, max_length),std::bind(&Session::HandlerRead, this, std::placeholders::_1, std::placeholders::_2));}void Session::HandlerRead(const boost::system::error_code& err, std::size_t bytes_transferred) {if (0 != err.value()) {std::cout << "read data failed!err_code is: " << err.value() << " .message: " << err.what() << std::endl;delete this;}else {std::cout << "receive data is: " << data_ << std::endl;//大部分服务器这样设计全双工通信memset(data_, 0, sizeof(data_));//继续让接收/读数据监听,这样就会造成删除bugsocket_.async_read_some(boost::asio::buffer(data_, sizeof(data_)), std::bind(&Session::HandlerRead, this, std::placeholders::_1, std::placeholders::_2));socket_.async_send(boost::asio::buffer(data_, max_length),std::bind(&Session::HandleSend, this, std::placeholders::_1));}}void Session::HandleSend(const boost::system::error_code& err) {if (0 != err.value()) {std::cout << "send data failed!err code is: " << err.value() << " .message: " << err.what() << std::endl;}else {memset(data_, 0, sizeof(data_));//继续让接收/读数据监听socket_.async_read_some(boost::asio::buffer(data_, sizeof(data_)), std::bind(&Session::HandlerRead, this, std::placeholders::_1, std::placeholders::_2));}}
这是与之前提供的 Session 类相关的实现文件。解释这段代码:
Session::Session(boost::asio::io_context& io_context) : socket_(io_context){ memset(data_, 0, sizeof(data_));}
boost::asio::ip::tcp::socket& Session::GetSocket() { return socket_;}
void Session::Start() { memset(data_, 0, max_length); socket_.async_read_some(boost::asio::buffer(data_, max_length), std::bind(&Session::HandlerRead, this, std::placeholders::_1, std::placeholders::_2));}
void Session::HandlerRead(const boost::system::error_code& err, std::size_t bytes_transferred) { if (0 != err.value()) { std::cout << "read data failed! err_code is: " << err.value() << " . message: " << err.what() << std::endl; delete this; } else { std::cout << "receive data is: " << data_ << std::endl; // 大部分服务器这样设计全双工通信 memset(data_, 0, sizeof(data_)); // 继续让接收/读数据监听, 这样就会造成删除bug socket_.async_read_some(boost::asio::buffer(data_, sizeof(data_)), std::bind(&Session::HandlerRead, this, std::placeholders::_1, std::placeholders::_2)); socket_.async_send(boost::asio::buffer(data_, max_length), std::bind(&Session::HandleSend, this, std::placeholders::_1)); }}
void Session::HandleSend(const boost::system::error_code& err) { if (0 != err.value()) { std::cout << "send data failed! err code is: " << err.value() << " . message: " << err.what() << std::endl; delete this; } else { memset(data_, 0, sizeof(data_)); // 继续让接收/读数据监听 socket_.async_read_some(boost::asio::buffer(data_, sizeof(data_)), std::bind(&Session::HandlerRead, this, std::placeholders::_1, std::placeholders::_2)); }}
总的来说,这段代码是 Session 类的实现,它处理了异步的数据读取和发送操作,并提供了一些错误处理和数据清理的逻辑。这是一个基本的网络会话类的实现,用于处理网络通信。
Server类为服务器接收连接的管理类。
“server.h":
#pragma once#include #include #include"Session.h"class Server{public:Server(boost::asio::io_context& io_context, int16_t port);private:void StartAccept();void HandleAccept(Session* session, const boost::system::error_code& err);private:boost::asio::io_context& io_context_;boost::asio::ip::tcp::acceptor acceptor_;};
这段代码定义了一个名为 Server 的c++类,该类似乎用于创建和管理一个基于Boost.Asio库的TCP服务器。以下是对这段代码的解释:
#pragma once#include #include #include "Session.h"
class Server{public: Server(boost::asio::io_context& io_context, int16_t port);private: void StartAccept(); void HandleAccept(Session* session, const boost::system::error_code& err);private: boost::asio::io_context& io_context_; boost::asio::ip::tcp::acceptor acceptor_;};
Server::Server(boost::asio::io_context& io_context, int16_t port) : io_context_(io_context), acceptor_(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)){ StartAccept();}
void Server::StartAccept() { Session* new_session = new Session(io_context_); acceptor_.async_accept(new_session->GetSocket(), std::bind(&Server::HandleAccept, this, new_session, std::placeholders::_1));}
void Server::HandleAccept(Session* session, const boost::system::error_code& err) { if (!err) { session->Start(); } else { delete session; } StartAccept(); // 继续等待下一个连接}
总的来说,这段代码定义了一个基于Boost.Asio的TCP服务器类 Server,该类在构造函数中初始化了必要的成员变量并开始接受传入的连接。它使用了异步操作来处理连接请求,并在每次连接接受后启动一个新的会话(Session)。
“server.cpp":
#include"server.h"Server::Server(boost::asio::io_context& io_context,int16_t port):io_context_(io_context),acceptor_(io_context,boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),port)){StartAccept();}void Server::StartAccept() {Session* new_session = new Session(io_context_);acceptor_.async_accept(new_session->GetSocket(),std::bind(&Server::HandleAccept, this, new_session, std::placeholders::_1));}void Server::HandleAccept(Session* new_session, const boost::system::error_code& err){if (err.value() != 0){std::cout << "acceptor session failed.error_code is: " << err.value() << " .message: " << err.what() << std::endl;delete new_session;}else {std::cout << "accept new session success!" << std::endl;std::cout << "client connect,the ip:" << new_session->GetSocket().remote_endpoint().address() << std::endl;new_session->Start();}//继续监听新的客户端连接StartAccept();}
这段代码是C++的 server.cpp 文件,它实现了一个基于Boost.Asio库的TCP服务器类 Server 的成员函数。下面是对代码的详细解释:
Server::Server(boost::asio::io_context& io_context, int16_t port) : io_context_(io_context) , acceptor_(io_context, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)){ StartAccept();}
void Server::StartAccept() { Session* new_session = new Session(io_context_); acceptor_.async_accept(new_session->GetSocket(), std::bind(&Server::HandleAccept, this, new_session, std::placeholders::_1));}
void Server::HandleAccept(Session* new_session, const boost::system::error_code& err){ if (err.value() != 0) { std::cout << "acceptor session failed. error_code is: " << err.value() << " . message: " << err.what() << std::endl; delete new_session; } else { std::cout << "accept new session success!" << std::endl; std::cout << "client connect, the IP: " << new_session->GetSocket().remote_endpoint().address() << std::endl; new_session->Start(); } // 继续监听新的客户端连接 StartAccept();}
总的来说,这段代码是 Server 类的成员函数的实现,它用于接受客户端的连接请求,并在接受连接后启动会话。这是一个基本的TCP服务器的一部分,用于处理传入的连接请求。
“main.cpp”:
#include"server.h"int main() {try {boost::asio::io_context io_context;Server server(io_context, 9273);io_context.run();}catch (std::exception& e) {std::cout << "exception: " << e.what() << std::endl;}return 0;}
这段代码是一个C++程序的 main 函数,它创建了一个基于Boost.Asio库的TCP服务器并运行它。以下是对代码的详细解释:
#include "server.h"
boost::asio::io_context io_context;:创建了一个 io_context 对象,它用于管理异步操作。Boost.Asio库通常需要一个 io_context 对象来协调和管理异步操作。
Server server(io_context, 9273); 创建了一个 Server 类的对象 server,并传递了 io_context 对象和一个端口号(在此示例中是9273)作为参数。这样做将启动服务器并开始监听指定的端口。
io_context.run(); 调用 io_context 对象的 run 方法,开始运行事件循环,该事件循环会一直运行,直到没有待处理的异步操作。在这里,它将一直运行以监听和处理客户端连接请求。
catch (std::exception& e) { … }: 这是一个异常处理块,用于捕获任何可能抛出的异常。如果发生异常,它将打印异常的描述信息。
int main() { try { boost::asio::io_context io_context; Server server(io_context, 9273); io_context.run(); } catch (std::exception& e) { std::cout << "exception: " << e.what() << std::endl; } return 0;}
总的来说,这个 main 函数创建了一个TCP服务器,并通过调用 io_context.run() 启动服务器并进入事件循环,等待客户端连接请求。如果发生异常,它会捕获异常并打印错误信息。这是一个简单的服务器入口点,用于启动服务器应用程序。
客户端的设计用之前的同步模式即可,客户端不需要异步的方式,因为客户端并不是以并发为主,当然写成异步收发更好一些。 这里代码就不展示了,有兴趣去前一篇文章查看。
运行服务器之后再运行客户端,输入字符串后,就可以收到服务器应答的字符串了。
echo应答模式:
该demo示例为仿照asio官网编写的,其中存在隐患,就是当服务器即将发送数据前(调用async_write前),此刻客户端中断,服务器此时调用async_write会触发发送回调函数,判断ec为非0进而执行delete this逻辑回收session。但要注意的是客户端关闭后,在tcp层面会触发读就绪事件,服务器会触发读事件回调函数。在读事件回调函数中判断错误码ec为非0,进而再次执行delete操作,从而造成二次析构,这是极度危险的。
本文介绍了异步的应答服务器设计,但是这种服务器并不会在实际生产中使用,主要有两个原因:
来源地址:https://blog.csdn.net/qq_44918090/article/details/133349652
--结束END--
本文标题: 【boost网络库从青铜到王者】第七篇:asio网络编程中的异步echo服务器,以应答为主
本文链接: https://lsjlt.com/news/428355.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0