整理socket编程:boost::asio实现异步服务器

时间:2022-09-08 23:17:48

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1.前言</span>

前面文章已实现了调用win32 socket来实现同步服务器的开发,包括使用非阻塞模式+select I/O模型来实现非阻塞的服务器开发,本篇来介绍下boost::asio开源库来实现异步服务器的开发。

asio库是基于操作系统提供的异步机制,采用前摄器设计模式实现了可移植的异步(或者同步)IO操作,不要求使用多线程和锁,有效地避免了多线程编程带来的条件竞争,死锁等问题

2.线程安全问题

多线程调度情况:

asio规定:只能在调用io_service::run的线程中才能调用事件完成处理器。

注:事件完成处理器就是你async_accept、async_write等注册的句柄,类似于回调的东西。

单线程:

如果只有一个线程调用io_service::run,根据asio的规定,事件完成处理器也只能在这个线程中执行。也就是说,你所有代码都在同一个线程中运行,因此变量的访问是安全的。

多线程:

如果有多个线程同时调用io_service::run以实现多线程并发处理。对于asio来说,这些线程都是平等的,没有主次之分。如果你投递的一个请求比如async_write完成时,asio将随机的激活调用io_service::run的线程。并在这个线程中调用事件完成处理器(async_write当时注册的句柄)。如果你的代码耗时较长,这个时候你投递的另一个async_write请求完成时,asio将不等待你的代码处理完成,它将在另外的一个调用io_service::run线程中,调用async_write当时注册的句柄。也就是说,你注册的事件完成处理器有可能同时在多个线程中调用。

参考 http://www.cnblogs.com/lidabo/p/3906055.html

3.简易异步服务器实现

//异步非阻塞服务器,利用Boost::asio
using namespace boost::asio;
struct CHelloService
{
io_service& m_ioservice;
ip::tcp::acceptor m_acceptor;

CHelloService(io_service& io)
:m_ioservice(io)
,m_acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), 2000)){}

void Start()
{
//等待连接,非阻塞
boost::shared_ptr<ip::tcp::socket> pSocket(new ip::tcp::socket(m_ioservice));
m_acceptor.async_accept(*pSocket, boost::bind(&CHelloService::Accept_handler, this, pSocket, _1));
}

//有客户端连接时,触发Accept_handler
void Accept_handler(boost::shared_ptr<ip::tcp::socket> psocket, boost::system::error_code ec)
{
if (ec)
{
return;
}
std::cout << psocket->remote_endpoint().address() << std::endl;
//发送消息
boost::shared_ptr<std::string> pstr(new std::string("hello async world!"));
psocket->async_write_some(buffer(*pstr), boost::bind(&CHelloService::Write_handler, this, pstr, _1, _2));
//继续等待连接
Start();
}

//异步写完成后触发Write_handler
void Write_handler(boost::shared_ptr<std::string> pstr, boost::system::error_code ec, size_t bytes_transferred)
{
if (ec)
{
std::cout << "发送失败!" << std::endl;
}
else
{
std::cout << *pstr << "已发出" << std::endl;
}
}
};

int AsyncAsioSvr()
{
boost::asio::io_service io_svr;
CHelloService hello_svr(io_svr);
hello_svr.Start();
io_svr.run();
return 0;
}