您的位置:首页 > 理论基础 > 计算机网络

boost::asio 连接管理1

2013-01-13 17:20 411 查看
在完成了第一个基于boost::asio的通信服务程序后,回顾一下所用到的概念,参考一些资料。将用一个系列来归纳一下如何通过boost::asio编写高性能TCP服务程序。
本篇从简单的单线程开始,描述如何监听端口,接收连接请求。同时也复用了前面的“优雅的退出” 的代码。
首先main函数创建一个server对象,server对象负责监听本地8888端口,一旦有连接请求,则创建一个connection对象,并调用StartWork开始工作。
下面是代码:
#include <cstdlib>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>

using namespace boost;
using namespace boost::asio;
using ip::tcp;
using namespace std;
using boost::system::error_code;

class Connection {
public:
Connection(io_service& s): socket(s) {

}

~Connection() {
socket.close();
cout << "~Connection" << endl;
}

void StartWork() {
cout << "The new connection object is starting now." << endl;
}

public:
tcp::socket socket;
};

class Server {
public:

Server(io_service & s, tcp::endpoint const& listen_endpoint)
: io_(s), signals_(s), acceptor_(s, listen_endpoint) {
signals_.add(SIGINT);
signals_.add(SIGTERM);
#if defined(SIGQUIT)
signals_.add(SIGQUIT);
#endif
signals_.async_wait(boost::bind(&Server::Stop, this));
shared_ptr<Connection> c(new Connection(io_));
cout << "count1:" << c.use_count() << endl;
acceptor_.async_accept(c->socket,
boost::bind(&Server::AfterAccept, this, c, _1));
cout << "count2:" << c.use_count() << endl;
}

void Run() {
io_.run();
}

void AfterAccept(shared_ptr<Connection>& c, error_code const& ec) {
// Check whether the server was stopped by a signal before this completion
// handler had a chance to run.
if (!acceptor_.is_open()) {
return;
}

cout << "count3:" << c.use_count() << endl;

if (!ec) {
c->StartWork();

shared_ptr<Connection> c2(new Connection(io_));

acceptor_.async_accept(c2->socket,
boost::bind(&Server::AfterAccept, this, c2, _1));
}
}

private:

void Stop() {
cout << "stop io_service" << endl;
io_.stop();
}

private:
io_service& io_;
boost::asio::signal_set signals_;
tcp::acceptor acceptor_;
};

int main(int argc, char** argv) {
io_service s;

tcp::endpoint listen_endpoint(tcp::v4(), 8888);

Server server(s, listen_endpoint);
server.Run();
return 0;
}

代码有点长,但是和真正的产品来讲已经很简单了。
通过telnet localhost 8888 命令可以迅速测试一下,会看到连接已经建立,很快又被断开。
程序打印出两行消息:
The new connection object is starting now.
~Connection


这个关系到对象生命周期的问题。
先看Server的构造函数里面,创建了一个Connection对象,用shared_ptr管理,此时引用计数为1,然后在下面一句bind调用时,将c变量保存到bind_t中了,因此引用计数会增加到2, 之后构造函数结束,引用计数减到1.
asio回调bind_t对象的operator()() 的时候最终会调用到AfterAccept函数,c对象作为引用参数传递进来,因此参数传递没有增加引用计数。但是这中间的asio回调机制使得引用计数增加到2. 
然后里面运行了StartWork,StartWork很快返回。当AfterAccept函数退出时,asio的回调机制的清理将引用计数减到1, 而bind_t这个function object对象也被销毁,因此引用计数降到0,所以c的析构函数被调用。
bind内部的细节不去管他,这里只要注意一旦StartWork函数退出,对象就会被销毁。

由于在AfterAccept函数最后总是又调用一次async_accept函数,所以会一直不断的等待新的连接。直到io_service::stop函数被调用,才结束整个程序。
这个简单的例子是一个开始,也说明了连接是如何建立的,连接对象的生命周期是如此脆弱。后面会继续改进。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  boost asio tcp