boost.asio的异步echo服务器端的std::bind实现

C++11以来,提供了不少遍历,原来在boost库中的一些工具,也进入到了C++标准库中。boost作为“准”标准库也C++尽可能需要掌握的知识和技能。
现在采用std::bind方式实现异步echo服务器端,后面会采用lambda表达式重新实现一遍,比较二者的差异,采用自己喜欢的方法就可以了。
完整代码:

// Asynchronous echo server.

#include <array>
#include <functional>
#include <iostream>
#include <memory>
#include <string>

#include "boost/asio.hpp"
#include "boost/core/ignore_unused.hpp"

using boost::asio::ip::tcp;

enum { BUF_SIZE = 1024 };

class Session : public std::enable_shared_from_this<Session> {
public:
	Session(tcp::socket socket) : socket_(std::move(socket)) {
	}

	void Start() {
		DoRead();
	}

private:
	void DoRead() {
		socket_.async_read_some(boost::asio::buffer(buffer_),
			std::bind(&Session::OnRead, shared_from_this(),
				std::placeholders::_1,
				std::placeholders::_2));
	}

	void DoWrite(std::size_t length) {
		boost::asio::async_write(socket_,
			boost::asio::buffer(buffer_, length),
			std::bind(&Session::OnWrite, shared_from_this(),
				std::placeholders::_1,
				std::placeholders::_2));
	}

	void OnRead(boost::system::error_code ec, std::size_t length) {
		if (!ec) {
			DoWrite(length);
		}
		else {
			if (ec == boost::asio::error::eof) {
				std::cerr << "Socket read EOF: " << ec.message() << std::endl;
			}
			else if (ec == boost::asio::error::operation_aborted) {
				// The socket of this connection has been closed.
				// This happens, e.g., when the server was stopped by a signal (Ctrl-C).
				std::cerr << "Socket operation aborted: " << ec.message() << std::endl;
			}
			else {
				std::cerr << "Socket read error: " << ec.message() << std::endl;
			}
		}
	}

	void OnWrite(boost::system::error_code ec, std::size_t length) {
		boost::ignore_unused(length);

		if (!ec) {
			DoRead();
		}
	}

	tcp::socket socket_;
	std::array<char, BUF_SIZE> buffer_;
};

class Server {
public:
	Server(boost::asio::io_context& io_context, std::uint16_t port)
		: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {
		DoAccept();
	}

private:
	void DoAccept() {
		acceptor_.async_accept(std::bind(&Server::accept_handler, this, 
							   std::placeholders::_1, 
							   std::placeholders::_2));
	}

	void accept_handler(const boost::system::error_code& error,
		boost::asio::ip::tcp::socket peer)
	{
		if (!error)
		{
			// Accept succeeded.
			std::make_shared<Session>(std::move(peer))->Start();
		}
		DoAccept();
	}

	tcp::acceptor acceptor_;
};

int main(int argc, char* argv[]) {
	if (argc != 2) {
		std::cerr << "Usage: " << argv[0] << " <port>" << std::endl;
		return 1;
	}

	std::uint16_t port = std::atoi(argv[1]);

	boost::asio::io_context io_context;

	Server server{ io_context, port };

	io_context.run();

	return 0;
}

题外话:关于帮助文档的查询
在这里插入图片描述
在你的boost目录中是有文档可以查询的,比如我这里的boosts 1.7.2中帮助文档如图所示,打开reference.html这个网页,就可以看到所有类的索引,非常方便。

讲解:
先从Server的构造函数说起

Server(boost::asio::io_context& io_context, std::uint16_t port)
		: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {
		DoAccept();
	}

这里的tcp::acceptor的头文件在boost/asio/ip/tcp.hpp中
在这个头文件中看到其构造函数:

  /// The TCP acceptor type.
  typedef basic_socket_acceptor<tcp> acceptor;

然后我们去看basic_socket_acceptor的构造函数

basic_socket_acceptor::async_accept

然后看到一堆模板重载的

template<
    typename MoveAcceptHandler = DEFAULT>
DEDUCED async_accept(
    MoveAcceptHandler && handler = DEFAULT);

这个是我们用的,然后我又去查这个MoveAcceptHandler
会看到几种写法,有普通函数的写法,仿函数的写法和lambda表达式的写法,还介绍了std::bind的写法
初学boost.asio会发现到处都是模板,函数模板,类模板,查帮助文档也似乎不那么方便,慢慢会习惯的。

构造函数构造完成后,就开始了DoAccept();
这个函数的作用的不断接收新的请求,然后利用socket,构造一个Session,在Session中处理tcp数据的接收和发送。
在Session中boost::asio::async_read_some,不断读,读一点,就用boost::asio::async_write写一点,直到async_read_some读到结束,或者socket被动关闭,或者有错误发生。然后Session就完成了自动的使命,自动析构。
因为Session接收数据和发送数据都是异步的,就利用了std::shared_ptr来延长生命周期,使得Session不被过早释放。具体智能指针延长生命周期的知识点,大家可以查std::enable_shared_from_this的用法。

客户端的话,可以用之前去同步echo客户端就可以,后面我们会继续实现一个异步echo客户端。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值