当前位置:编程学习 > 网站相关 >>

Boost::asio范例分析 服务端

   main函数要求程序调用者传递3个参数:服务器IP地址,端口号和文档根目录.其中IP地址可以是IPv4或IPv6格式.接着创建server对象实例,将传递进来的IP地址,端口号,文档根目录作为server对象的构造函数参数传递到处理程序中.最后调用server的run成员函数启动服务端处理例程.
    http::server::server s(argv[1], argv[2], argv[3]);
  s.run();
  首先看看server类的定义和实现.为防止server对象被拷贝复制,这个类从boost::noncopyable类私有继承.这个类主要用来控制服务端核心代码的运行,管理tcp链接请求,建立链接缓冲池等功能.
  Server类定义的数据成员:
1) boost::asio::io_service io_service_;这个对象很熟悉了,用来执行异步操作.
2) boost::asio::signal_set signals_;信号集合用来注册程序结束信号,以便于退出时释放资源.
3) boost::asio::ip::tcp::acceptor acceptor_;接收器用来侦听到来的链接请求.
4) connection_manager connection_manager_;连接池用来管理所有活动的链接.
5) connection_ptr new_connection_;这是一个shared_ptr类型,用来存放新建的链接,是实现链接自动释放的关键.
6) request_handler request_handler_;请求处理器,用来处理所有到来的请求.
  Server类的函数成员:
1) 构造函数:构造函数初始化了上述的数据成员,并向signals_信号集合中添加程序发生中断和结束的信号,并在信号集合上设置异步等待,当集合中的信号受信后执行server::handle_stop函数,结束当前运行的链接对象.接着根据传入的服务器地址参数得到端点,与接收器绑定开始侦听客户端的链接,并执行start_accept函数成员,处理到来的链接请求.
server::server(const std::string& address, const std::string& port,
    const std::string& doc_root)
  : io_service_(),
    signals_(io_service_),
    acceptor_(io_service_),
    connection_manager_(),
    new_connection_(),
    request_handler_(doc_root)
{
  signals_.add(SIGINT);
  signals_.add(SIGTERM);
#if defined(SIGQUIT)
  signals_.add(SIGQUIT);
#endif // defined(SIGQUIT)
  signals_.async_wait(boost::bind(&server::handle_stop, this));

  boost::asio::ip::tcp::resolver resolver(io_service_);
  boost::asio::ip::tcp::resolver::query query(address, port);
  boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
  acceptor_.open(endpoint.protocol());
  acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
  acceptor_.bind(endpoint);
  acceptor_.listen();

  start_accept();
}
2) Server::run函数:
这个函数实现比较简单,调用io_service_.run();函数启动异步操作.
3) Server::start_accept函数:
这个函数首先创建一个新的链接对象,并使用new_connection_对象来保证自动释放(引用计数减一).通过shared_ptr类的reset成员函数,使new_connection_释放掉原来持有的链接对象,转而管理新建的链接.接着启动异步接收操作,收到异步链接后,执行server::handle_accept函数.注意connection类的构造函数接收一个链接池对象,创建好链接后自动将链接放入缓冲池进行管理.
void server::start_accept()
{
  new_connection_.reset(new connection(io_service_,
        connection_manager_, request_handler_));
  acceptor_.async_accept(new_connection_->socket(),
      boost::bind(&server::handle_accept, this,
        boost::asio::placeholders::error));
}
4) server::handle_accept函数:
这个函数启动链接对象的处理流程,并调用start_accept继续接收到来的客户端链接.这个函数与start_accept函数构成了递归调用,异步接收到链接后进行处理并再次启动异步链接.
void server::handle_accept(const boost::system::error_code& e)
{
  if (!acceptor_.is_open())
  {
    return;
  }
  if (!e)
  {
    connection_manager_.start(new_connection_);
  }
  start_accept();
}
5) server::handle_stop函数:
这个函数由信号集合受信后异步除法,用来停止接收器,停止当前链接处理例程.
void server::handle_stop()
{
  acceptor_.close();
  connection_manager_.stop_all();
}
接下来分析一下connection类.这个类从enable_shared_from_this<connection>类和noncopyable类继承,前一个父类提供了shared_from_this()成员函数,返回持有this指针的shared_ptr对象,实现了自动内存回收.后一个基类防止对象被拷贝复制.这个类的实现与asio的echo服务端范例很相似,只增加了解析http协议包的对象成员和连接池成员.
Connection类的数据成员:
1) boost::asio::ip::tcp::socket socket_;链接的socket对象,用来进行与客户端通信.
2) connection_manager& connection_manager_;连接池对象
3) request_handler& request_handler_;请求处理对象
4) boost::array<char, 8192> buffer_;接收客户端数据的缓冲区
5) request request_;请求对象
6) request_parser request_parser_;请求解析对象
7) reply reply_;应答对象
   Connection类的函数成员:
1) 构造函数:
这里只是初始化了上述的数据成员.
connection::connection(boost::asio::io_service& io_service,
    connection_manager& manager, request_handler& handler)
  : socket_(io_service),
    connection_manager_(manager),
    request_handler_(handler)
{
}
2) connection::socket函数:
简单的返回链接的socket对象.
3) Connection::start函数:
这个函数启动异步接收客户端数据操作.接收到数据存入数据成员buffer_中后调用handle_read函数进行处理.注意async_read_some接收数据后马上返回,不会判断接收到的数据大小.如果使用全局async_read函数则必须在缓冲区被填满后才返回.
void connection::start()
{
  socket_.async_read_some(boost::asio::buffer(buffer_),
      boost::bind(&connection::handle_read, shared_from_this(),
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));
}
4) Connection::stop函数:
函数简单的调用socket_close()停止socket对象.
5) Connection::handle_read函数:
这个函数处理connection对象的核心逻辑,接收到数据后,处理http请求,解析成功则根据请求组织响应信息发送给客户端.如果解析失败则向客户端发送错误信息.
void connection::handle_read(const boost::system::error_code& e,
    std::size_t bytes_transferred)
{
  if (!e)//接收时没有发生错误
  {
boost::tribool result;//三状态bool类型
// boost::tie构造一个类似pair的对象,用来接收函数的多个返回值
//这里解析接收到http请求,并将解析结果存入request_结构体中.
    boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
        request_, buffer_.data(), buffer_.data() + bytes_transferred);
    if (result)//如果解析成功
    {
      request_handler_.handle_request(request_, reply_);//处理请求,生成响应数据
      boost::asio::async_write(socket_, reply_.to_buffers(),//发送响应数据
          boost::bind(&connection::handle_write, shared_from_this(),
            boost::asio::placeholders::error));
    }
    else if (!result)//解析失败,则想客户端发送错误信息
    {
      reply_ = reply::stock_reply(reply::bad_request);
      boost::asio::async_write(socket_, reply_.to_buffers(),
          boost::bind(&connection::handle_write, shared_from_this(),
         

补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,