五、实现基于官方案例的异步server

        系列文章目录:C++ asio网络编程-CSDN博客

        在上一小节中,我们介绍了boost::asio中的异步读写api,这一小节就是使用这些api去实现一个异步读写的server。

1、Session类

        Session类主要是处理客户端消息收发的会话类,为了简单起见,我们不考虑粘包问题,也不考虑支持手动调用发送的接口,只以应答的方式发送和接收固定长度(1024字节长度)的数据。

class Session
{
public:
	Session(boost::asio::io_context& ioc);

	boost::asio::ip::tcp::socket& getSocket();

	void start();

private:
	void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
	void handle_write(const boost::system::error_code& ec);

	boost::asio::ip::tcp::socket _socket;
	enum {MAX_LENGTH = 1024};
	char _data[MAX_LENGTH];
};
  • _data用来接收客户端传递的数据
  •  _socket为单独处理客户端读写的socket。
  • handle_read和handle_write分别为读回调函数和写回调函数。 

         接下来我们去是实现他们

Session::Session(boost::asio::io_context& ioc) : _socket(ioc)
{
}

boost::asio::ip::tcp::socket& Session::getSocket()
{
	return _socket;
}

// 在Start方法中我们调用异步读操作,
// 监听对端发送的消息。当对端发送数据后,触发handle_read函数
void Session::start()
{
	memset(_data, 0, MAX_LENGTH);
	_socket.async_read_some(
		boost::asio::buffer(_data, MAX_LENGTH),
		std::bind(&Session::handle_read, this, std::placeholders::_1, std::placeholders::_2)
	);
}

// handle_read函数内将收到的数据发送给对端,
// 当发送完成后触发handle_write回调函数。
void Session::handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred)
{
	if (!ec) {
		std::cout << "server receive data is " << _data << std::endl;
		boost::asio::async_write(_socket,
			boost::asio::buffer(_data, bytes_transferred),
			std::bind(&Session::handle_write, this, std::placeholders::_1));
	}
	else {
		std::cout << "read error" << std::endl;
		delete this;
	}
}

// handle_write函数内又一次监听了读事件,
// 如果对端有数据发送过来则触发handle_read,我们再将收到的数据发回去。
// 从而达到应答式服务的效果。
void Session::handle_write(const boost::system::error_code& ec)
{
	if (!ec) {
		// 发完后继续去读
		memset(_data, 0, MAX_LENGTH);
		_socket.async_read_some(
			boost::asio::buffer(_data, MAX_LENGTH),
			std::bind(&Session::handle_read, this, std::placeholders::_1, std::placeholders::_2)
		);
	}
	else {
		std::cout << "write error" << ec.value() << std::endl;
		delete this;
	}
}

2、Server类

        Server类为服务器接收连接的管理类

class Server
{
public:
	Server(boost::asio::io_context& ioc, unsigned short port);

private:
	void start_accept();
	void handle_accept(Session* new_session, const boost::system::error_code& ec);

	boost::asio::io_context& _ioc;  // io_context不允许被复制
	boost::asio::ip::tcp::acceptor _acceptor;
};
  • start_accept将要接收连接的acceptor绑定到服务上。
  • handle_accept为新连接到来后触发的回调函数。

        接下来是函数实现

Server::Server(boost::asio::io_context& ioc, unsigned short port)
	: _ioc(ioc), 
	_acceptor(ioc, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
{
	std::cout << "Server start success, on port: " << port << std::endl;
	start_accept();
}

void Server::start_accept()
{
	Session* new_session = new Session(_ioc);

	_acceptor.async_accept(new_session->getSocket(),
		std::bind(&Server::handle_accept, this, new_session,std::placeholders::_1));
}

void Server::handle_accept(Session* new_session, const boost::system::error_code& ec)
{
	if (!ec) {
		new_session->start();
	}
	else {
		delete new_session;
	}

	start_accept();
}

3、客户端

        客户端的设计用第三节中的同步模式即可,客户端不需要异步的方式,因为客户端并不是以并发为主,当然写成异步收发更好一些。

4、运行结果

5、总结

        到这里依然是白雪,也是不会再实际项目中使用的,主要有以下原因

  • 因为该服务器的发送和接收以应答的方式交互,而并不能做到应用层想随意发送的目的,也就是未做到完全的收发分离(全双工逻辑)。
  • 该服务器未处理粘包,序列化,以及逻辑和收发线程解耦等问题。

        这些问题我们会在接下来的文章中不断完善。 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值