boost asio异步服务端实现步骤

4 篇文章 0 订阅
3 篇文章 0 订阅

(1)首先要初始化一个io_service,并且调用run方法运行起来

boost::asio::io_service iosrv;

iosrv.run();

(2)然后需要用一个iosrv的实例来初始化一个acceptor

boost::asio::ip::tcp::acceptor acceptor(iosrv);

(3)然后需要调用acceptor对象的open函数

boost::system::error_code ec;

acceptor.open(boost::asio::ip::tcp::v4(), ec);

(4)然后调用acceptor的bind函数绑定ip和端口,协议等

    m_acceptor.set_option(boost::asio::socket_base::reuse_address(true) );

    m_acceptor.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), ec);

(5)然后调用accptor的listen函数进行监听

acceptor.listen(10);

(6)然后调用acceptor的async_accept函数异步接受一个连接

    boost::asio::ip::tcp::socket m_sock;

     m_acceptor.async_accept(m_sock, std::bind(&server::on_accept, this, std::placeholders::_1));

   其中m_sock 接受新连接后保存连接信息的载体

需要注意的是,当接受一个连接完成后需要再次调用m_acceptor的async_accept函数,才会再次接受下一个连接,否则不会接受新的连接

(8)接收消息可以使用tcp::socket 对象的async_read_some方法(这个函数不一定读取锁期望的全部字节就可能返回)

    void async_read()
    {
        auto self(shared_from_this());
        m_socket.async_read_some(boost::asio::buffer(m_buff), 
            [this, self](const boost::system::error_code &ec, size_t byte_transffered) {
            if (!ec)
            {
                async_write(byte_transffered);
            }
            else
            {
                std::cout << "read error" << ec << std::endl;
            }
        });
        
    }

或者可以使用boost::asio::async_read方法,但是这个方法是读指定长度的数据,如果没有读到所期望的字节数,就不会返回,直到等到所有期待的字节或者出错的时候才返回,

boost::asio::async_read特别适合用来获取固定长度的包头和指定长度的包体,这个很适合解包

(9)发送消息可以用boost::asio::async_write()函数(不是socket类的成员函数)

    void async_write(size_t byte_transffered)
    {
        auto self(shared_from_this());
        boost::asio::async_write(m_socket, boost::asio::buffer(m_buff, byte_transffered),
            [this, self](const boost::system::error_code &ec, size_t sendsize)
        {
            if (!ec)
            {
                std::cout << "send " << sendsize << " byte success." << std::endl;
                async_read();
            }
            else
            {
                std::cout << "send fail." << std::endl;
            }

        }
            );
    }

如果初始化一个使用一个endpoint初始化一个acceptor,那么就不需要步骤(3)~(5),直接到调用acceptor::async_accept这一步,例如:

boost::asio::ip::tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port))

 

asio的异步实现机制:asio库使用epoll模型之所以能做到全异步,是因为有个io_service这个类,这个类里面会维护一个待执行的任务队列,某个线程会调用这个io_service的run方法,run方法中一直循环检测任务队列,如果有未执行的队列就执行,其他线程通过io_service的post方法,把需要执行的函数加入到任务队列里面,让执行io_service.run()方法的那个线程去执行。这样就能做到异步,任务函数执行完后可以做一个回调通知函数post方

boost的每个socket都要绑定一个io_service就是这个道理

下面是echo服务端的代码:

// boost_test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include <boost/asio.hpp>

class session : public std::enable_shared_from_this<session>
{
public:
	session(boost::asio::ip::tcp::socket s) : m_socket(std::move(s))
	{

	}
    
	void async_read()
	{
		auto self(shared_from_this());
		m_socket.async_read_some(boost::asio::buffer(m_buff),
	//    boost::asio::async_read(m_socket, boost::asio::buffer(m_buff),
			[this, self](const boost::system::error_code &ec, size_t byte_transffered) {
			if (!ec)
			{
				std::string str(m_buff.data(), byte_transffered);
				std::cout << "receive:" << str << std::endl;
				async_write(byte_transffered);
			}
			else
			{
				std::cout << "read error" << ec << std::endl;
			}
		});
		
	}

	void async_write(size_t byte_transffered)
	{
		auto self(shared_from_this());
		boost::asio::async_write(m_socket, boost::asio::buffer(m_buff, byte_transffered),
			[this, self](const boost::system::error_code &ec, size_t sendsize)
		{
			if (!ec)
			{
				std::cout << "send " << sendsize << " byte success." << std::endl;
				async_read();
			}
			else
			{
				std::cout << "send fail." << std::endl;
			}

		}
			);
	}

public:
	boost::asio::ip::tcp::socket m_socket;
	std::array<char, 1024> m_buff;
};


class server {
public:
	server(std::string ip, unsigned short port, boost::asio::io_service *pIoService):
		m_sock(*pIoService), m_acceptor(*pIoService)
	{
		boost::system::error_code ec;
		m_acceptor.open(boost::asio::ip::tcp::v4(), ec);
		if (ec)
			std::cout << "open error :" << ec << std::endl;
        m_acceptor.set_option(boost::asio::socket_base::reuse_address(true) );
		m_acceptor.bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), ec);
		if (ec)
			std::cout << "bind error :" << ec << std::endl;
		std::cout << "port:" <<  port << std::endl;
		m_acceptor.listen(10);
	}

	void async_accept()
	{
		m_acceptor.async_accept(m_sock, std::bind(&server::on_accept, this, std::placeholders::_1));
	}

	void on_accept(const boost::system::error_code &ec)
	{
		if (!ec)
		{
			std::shared_ptr<session> ptr = std::make_shared<session>(std::move(m_sock));
			ptr->async_read();
		}

		//重新获取连接
		async_accept();
	}

public:
	boost::asio::ip::tcp::socket m_sock;
	boost::asio::ip::tcp::acceptor m_acceptor;
};

int main()
{
	std::cout << "v2.2" << std::endl;
	boost::asio::io_service ioservice;
	server sv("", 9000, &ioservice);
	sv.async_accept();
	ioservice.run();
	std::cout << "end" <<  std::endl; 
}

参考博文:

https://www.cnblogs.com/hanerfan/p/5161955.html

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值