boost::asio httpserve httpserver2 httpserver3的比较

官网上的例子在这里https://www.boost.org/doc/libs/1_67_0/doc/html/boost_asio/examples/cpp03_examples.html

一 http::server 只有一个主线程

首先http::server是一个简单的单线程服务器,只有一个主线程;

httpserver的思想比较简单:主线程先预先申请一个连接对象connection并使用的acceptor对connection对象监听客户端的连接,连接到来后将该连接加入到连接管理connection_manager数组中,并重新预分配一个连接对象开始新一轮监听;

connection_manager调用connection的start()函数,开始向io_context投递接收请求,接收请求处理完后调用回调函数handle_read进行处理,并开始新一轮投递接收请求;

里面比较重要的文件是

server.hpp server.cpp

 connection.hpp connection.cpp

connection_manager.hpp connection_manager.cpp

main.cpp

其他文件在这三个server中是一样的,用于处理接收和回复,这里不予讨论。

connection作用:处理接收,发送请求

connection.hpp源码如下:

 1 //
 2 // connection.hpp
 3 // ~~~~~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #ifndef HTTP_CONNECTION_HPP
12 #define HTTP_CONNECTION_HPP
13 
14 #include <boost/asio.hpp>
15 #include <boost/array.hpp>
16 #include <boost/noncopyable.hpp>
17 #include <boost/shared_ptr.hpp>
18 #include <boost/enable_shared_from_this.hpp>
19 #include "reply.hpp"
20 #include "request.hpp"
21 #include "request_handler.hpp"
22 #include "request_parser.hpp"
23 
24 namespace http {
25 namespace server {
26 
27 class connection_manager;
28 
29 /// Represents a single connection from a client.
30 class connection
31   : public boost::enable_shared_from_this<connection>,
32     private boost::noncopyable
33 {
34 public:
35   /// Construct a connection with the given io_context.
36   explicit connection(boost::asio::io_context& io_context,
37       connection_manager& manager, request_handler& handler);
38 
39   /// Get the socket associated with the connection.
40   boost::asio::ip::tcp::socket& socket();
41 
42   /// Start the first asynchronous operation for the connection.
43   void start();
44 
45   /// Stop all asynchronous operations associated with the connection.
46   void stop();
47 
48 private:
49   /// Handle completion of a read operation.
50   void handle_read(const boost::system::error_code& e,
51       std::size_t bytes_transferred);
52 
53   /// Handle completion of a write operation.
54   void handle_write(const boost::system::error_code& e);
55 
56   /// Socket for the connection.
57   boost::asio::ip::tcp::socket socket_;
58 
59   /// The manager for this connection.
60   connection_manager& connection_manager_;
61 
62   /// The handler used to process the incoming request.
63   request_handler& request_handler_;
64 
65   /// Buffer for incoming data.
66   boost::array<char, 8192> buffer_;
67 
68   /// The incoming request.
69   request request_;
70 
71   /// The parser for the incoming request.
72   request_parser request_parser_;
73 
74   /// The reply to be sent back to the client.
75   reply reply_;
76 };
77 
78 typedef boost::shared_ptr<connection> connection_ptr;
79 
80 } // namespace server
81 } // namespace http
82 
83 #endif // HTTP_CONNECTION_HPP
View Code
connection_manager& connection_manager_用来对当前所有的连接进行管理;

connection.cpp源码如下:
 1 //
 2 // connection.cpp
 3 // ~~~~~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #include "connection.hpp"
12 #include <vector>
13 #include <boost/bind.hpp>
14 #include "connection_manager.hpp"
15 #include "request_handler.hpp"
16 
17 namespace http {
18 namespace server {
19 
20 connection::connection(boost::asio::io_context& io_context,
21     connection_manager& manager, request_handler& handler)
22   : socket_(io_context),
23     connection_manager_(manager),
24     request_handler_(handler)
25 {
26 }
27 
28 boost::asio::ip::tcp::socket& connection::socket()
29 {
30   return socket_;
31 }
32 
33 void connection::start()
34 {
35   socket_.async_read_some(boost::asio::buffer(buffer_),
36       boost::bind(&connection::handle_read, shared_from_this(),
37         boost::asio::placeholders::error,
38         boost::asio::placeholders::bytes_transferred));
39 }
40 
41 void connection::stop()
42 {
43   socket_.close();
44 }
45 
46 void connection::handle_read(const boost::system::error_code& e,
47     std::size_t bytes_transferred)
48 {
49   if (!e)
50   {
51     boost::tribool result;
52     boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
53         request_, buffer_.data(), buffer_.data() + bytes_transferred);
54 
55     if (result)
56     {
57       request_handler_.handle_request(request_, reply_);
58       boost::asio::async_write(socket_, reply_.to_buffers(),
59           boost::bind(&connection::handle_write, shared_from_this(),
60             boost::asio::placeholders::error));
61     }
62     else if (!result)
63     {
64       reply_ = reply::stock_reply(reply::bad_request);
65       boost::asio::async_write(socket_, reply_.to_buffers(),
66           boost::bind(&connection::handle_write, shared_from_this(),
67             boost::asio::placeholders::error));
68     }
69     else
70     {
71       socket_.async_read_some(boost::asio::buffer(buffer_),
72           boost::bind(&connection::handle_read, shared_from_this(),
73             boost::asio::placeholders::error,
74             boost::asio::placeholders::bytes_transferred));
75     }
76   }
77   else if (e != boost::asio::error::operation_aborted)
78   {
79     connection_manager_.stop(shared_from_this());
80   }
81 }
82 
83 void connection::handle_write(const boost::system::error_code& e)
84 {
85   if (!e)
86   {
87     // Initiate graceful connection closure.
88     boost::system::error_code ignored_ec;
89     socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
90   }
91 
92   if (e != boost::asio::error::operation_aborted)
93   {
94     connection_manager_.stop(shared_from_this());
95   }
96 }
97 
98 } // namespace server
99 } // namespace http
View Code

boost::bind用来产生一个函数对象,在本文中可以理解成使用boost::bind来注册回调函数即可。

start()函数:
向io_context投递接收数据请求,并注册请求处理完后的回调函数handle_read()

handle_read()函数:
对接收到的数据进行分析,
如果成功或失败都向客户端发送一个答复,即向Io_context投递一个发送请求,并注册答复发送完后的回调处理函数handle_write();
如果分析结果为不确定,则继续向io_context投递一个接收请求;

handle_write()函数:
判断是否向客户端发送成功,如果成功后则优雅的关闭本次连接,
如果发送失败且失败码不为operation_aborted则调用connection_manager来终止本次连接。


server类作用:绑定、监听客户端连接的到来
server.hpp源代码如下:
 1 //
 2 // server.hpp
 3 // ~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #ifndef HTTP_SERVER_HPP
12 #define HTTP_SERVER_HPP
13 
14 #include <boost/asio.hpp>
15 #include <string>
16 #include <boost/noncopyable.hpp>
17 #include "connection.hpp"
18 #include "connection_manager.hpp"
19 #include "request_handler.hpp"
20 
21 namespace http {
22 namespace server {
23 
24 /// The top-level class of the HTTP server.
25 class server
26   : private boost::noncopyable
27 {
28 public:
29   /// Construct the server to listen on the specified TCP address and port, and
30   /// serve up files from the given directory.
31   explicit server(const std::string& address, const std::string& port,
32       const std::string& doc_root);
33 
34   /// Run the server's io_context loop.
35   void run();
36 
37 private:
38   /// Initiate an asynchronous accept operation.
39   void start_accept();
40 
41   /// Handle completion of an asynchronous accept operation.
42   void handle_accept(const boost::system::error_code& e);
43 
44   /// Handle a request to stop the server.
45   void handle_stop();
46 
47   /// The io_context used to perform asynchronous operations.
48   boost::asio::io_context io_context_;
49 
50   /// The signal_set is used to register for process termination notifications.
51   boost::asio::signal_set signals_;
52 
53   /// Acceptor used to listen for incoming connections.
54   boost::asio::ip::tcp::acceptor acceptor_;
55 
56   /// The connection manager which owns all live connections.
57   connection_manager connection_manager_;
58 
59   /// The next connection to be accepted.
60   connection_ptr new_connection_;
61 
62   /// The handler for all incoming requests.
63   request_handler request_handler_;
64 };
65 
66 } // namespace server
67 } // namespace http
68 
69 #endif // HTTP_SERVER_HPP
View Code
io_context_:用来执行整个程序的异步操作;
acceptor_:用来设置socket属性,绑定和监听;

server.cpp源代码如下:
 1 //
 2 // server.cpp
 3 // ~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #include "server.hpp"
12 #include <boost/bind.hpp>
13 #include <signal.h>
14 
15 namespace http {
16 namespace server {
17 
18 server::server(const std::string& address, const std::string& port,
19     const std::string& doc_root)
20   : io_context_(),
21     signals_(io_context_),
22     acceptor_(io_context_),
23     connection_manager_(),
24     new_connection_(),
25     request_handler_(doc_root)
26 {
27   // Register to handle the signals that indicate when the server should exit.
28   // It is safe to register for the same signal multiple times in a program,
29   // provided all registration for the specified signal is made through Asio.
30   signals_.add(SIGINT);
31   signals_.add(SIGTERM);
32 #if defined(SIGQUIT)
33   signals_.add(SIGQUIT);
34 #endif // defined(SIGQUIT)
35   signals_.async_wait(boost::bind(&server::handle_stop, this));
36 
37   // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
38   boost::asio::ip::tcp::resolver resolver(io_context_);
39   boost::asio::ip::tcp::endpoint endpoint =
40     *resolver.resolve(address, port).begin();
41   acceptor_.open(endpoint.protocol());
42   acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
43   acceptor_.bind(endpoint);
44   acceptor_.listen();
45 
46   start_accept();
47 }
48 
49 void server::run()
50 {
51   // The io_context::run() call will block until all asynchronous operations
52   // have finished. While the server is running, there is always at least one
53   // asynchronous operation outstanding: the asynchronous accept call waiting
54   // for new incoming connections.
55   io_context_.run();
56 }
57 
58 void server::start_accept()
59 {
60   new_connection_.reset(new connection(io_context_,
61         connection_manager_, request_handler_));
62   acceptor_.async_accept(new_connection_->socket(),
63       boost::bind(&server::handle_accept, this,
64         boost::asio::placeholders::error));
65 }
66 
67 void server::handle_accept(const boost::system::error_code& e)
68 {
69   // Check whether the server was stopped by a signal before this completion
70   // handler had a chance to run.
71   if (!acceptor_.is_open())
72   {
73     return;
74   }
75 
76   if (!e)
77   {
78     connection_manager_.start(new_connection_);
79   }
80 
81   start_accept();
82 }
83 
84 void server::handle_stop()
85 {
86   // The server is stopped by cancelling all outstanding asynchronous
87   // operations. Once all operations have finished the io_context::run() call
88   // will exit.
89   acceptor_.close();
90   connection_manager_.stop_all();
91 }
92 
93 } // namespace server
94 } // namespace http
View Code

connection_manager类用来管理所有的已连接对象;

connection_manager.hpp的源代码如下:

 1 //
 2 // connection_manager.hpp
 3 // ~~~~~~~~~~~~~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #ifndef HTTP_CONNECTION_MANAGER_HPP
12 #define HTTP_CONNECTION_MANAGER_HPP
13 
14 #include <set>
15 #include <boost/noncopyable.hpp>
16 #include "connection.hpp"
17 
18 namespace http {
19 namespace server {
20 
21 /// Manages open connections so that they may be cleanly stopped when the server
22 /// needs to shut down.
23 class connection_manager
24   : private boost::noncopyable
25 {
26 public:
27   /// Add the specified connection to the manager and start it.
28   void start(connection_ptr c);
29 
30   /// Stop the specified connection.
31   void stop(connection_ptr c);
32 
33   /// Stop all connections.
34   void stop_all();
35 
36 private:
37   /// The managed connections.
38   std::set<connection_ptr> connections_;
39 };
40 
41 } // namespace server
42 } // namespace http
43 
44 #endif // HTTP_CONNECTION_MANAGER_HPP
View Code

connection_manager.cpp源代码如下:

 1 //
 2 // connection_manager.cpp
 3 // ~~~~~~~~~~~~~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #include "connection_manager.hpp"
12 #include <algorithm>
13 #include <boost/bind.hpp>
14 
15 namespace http {
16 namespace server {
17 
18 void connection_manager::start(connection_ptr c)
19 {
20   connections_.insert(c);
21   c->start();
22 }
23 
24 void connection_manager::stop(connection_ptr c)
25 {
26   connections_.erase(c);
27   c->stop();
28 }
29 
30 void connection_manager::stop_all()
31 {
32   std::for_each(connections_.begin(), connections_.end(),
33       boost::bind(&connection::stop, _1));
34   connections_.clear();
35 }
36 
37 } // namespace server
38 } // namespace http
View Code

最后在main.cpp中调用一个server对象开始服务的运行

main.cpp源代码如下:

 1 //
 2 // main.cpp
 3 // ~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #include <iostream>
12 #include <string>
13 #include <boost/asio.hpp>
14 #include <boost/bind.hpp>
15 #include "server.hpp"
16 
17 int main(int argc, char* argv[])
18 {
19   try
20   {
21     // Check command line arguments.
22     if (argc != 4)
23     {
24       std::cerr << "Usage: http_server <address> <port> <doc_root>\n";
25       std::cerr << "  For IPv4, try:\n";
26       std::cerr << "    receiver 0.0.0.0 80 .\n";
27       std::cerr << "  For IPv6, try:\n";
28       std::cerr << "    receiver 0::0 80 .\n";
29       return 1;
30     }
31 
32     // Initialise the server.
33     http::server::server s(argv[1], argv[2], argv[3]);
34 
35     // Run the server until stopped.
36     s.run();
37   }
38   catch (std::exception& e)
39   {
40     std::cerr << "exception: " << e.what() << "\n";
41   }
42 
43   return 0;
44 }
View Code

httpserver1比较简单接下来我们看看Server2

二 http::server2  多个线程多个io_context

http server2的思想是每个线程分配一个io_context,让每个线程都调用自己io_context::run函数,这样可以保证每个线程访问自己关联的io_context的任务队列。

http::server2::server相比较http::serve::server,去掉了connection_manager,增加了io_context_pool;

io_context_pool为每个线程分配一个io_context,

io_context_pool的源码如下:

 1 //
 2 // io_context_pool.hpp
 3 // ~~~~~~~~~~~~~~~~~~~
 4 //
 5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 6 //
 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 9 //
10 
11 #ifndef HTTP_SERVER2_IO_SERVICE_POOL_HPP
12 #define HTTP_SERVER2_IO_SERVICE_POOL_HPP
13 
14 #include <boost/asio.hpp>
15 #include <list>
16 #include <vector>
17 #include <boost/noncopyable.hpp>
18 #include <boost/shared_ptr.hpp>
19 
20 namespace http {
21 namespace server2 {
22 
23 /// A pool of io_context objects.
24 class io_context_pool
25   : private boost::noncopyable
26 {
27 public:
28   /// Construct the io_context pool.
29   explicit io_context_pool(std::size_t pool_size);
30 
31   /// Run all io_context objects in the pool.
32   void run();
33 
34   /// Stop all io_context objects in the pool.
35   void stop();
36 
37   /// Get an io_context to use.
38   boost::asio::io_context& get_io_context();
39 
40 private:
41   typedef boost::shared_ptr<boost::asio::io_context> io_context_ptr;
42   typedef boost::asio::executor_work_guard<
43     boost::asio::io_context::executor_type> io_context_work;
44 
45   /// The pool of io_contexts.
46   std::vector<io_context_ptr> io_contexts_;
47 
48   /// The work that keeps the io_contexts running.
49   std::list<io_context_work> work_;
50 
51   /// The next io_context to use for a connection.
52   std::size_t next_io_context_;
53 };
54 
55 } // namespace server2
56 } // namespace http
57 
58 #endif // HTTP_SERVER2_IO_SERVICE_POOL_HPP
//
// io_context_pool.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include "server.hpp"
#include <stdexcept>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

namespace http {
namespace server2 {

io_context_pool::io_context_pool(std::size_t pool_size)
  : next_io_context_(0)
{
  if (pool_size == 0)
    throw std::runtime_error("io_context_pool size is 0");

  // Give all the io_contexts work to do so that their run() functions will not
  // exit until they are explicitly stopped.
  for (std::size_t i = 0; i < pool_size; ++i)
  {
    io_context_ptr io_context(new boost::asio::io_context);
    io_contexts_.push_back(io_context);
    work_.push_back(boost::asio::make_work_guard(*io_context));
  }
}

void io_context_pool::run()
{
  // Create a pool of threads to run all of the io_contexts.
  std::vector<boost::shared_ptr<boost::thread> > threads;
  for (std::size_t i = 0; i < io_contexts_.size(); ++i)
  {
    boost::shared_ptr<boost::thread> thread(new boost::thread(
          boost::bind(&boost::asio::io_context::run, io_contexts_[i])));
    threads.push_back(thread);
  }

  // Wait for all threads in the pool to exit.
  for (std::size_t i = 0; i < threads.size(); ++i)
    threads[i]->join();
}

void io_context_pool::stop()
{
  // Explicitly stop all io_contexts.
  for (std::size_t i = 0; i < io_contexts_.size(); ++i)
    io_contexts_[i]->stop();
}

boost::asio::io_context& io_context_pool::get_io_context()
{
  // Use a round-robin scheme to choose the next io_context to use.
  boost::asio::io_context& io_context = *io_contexts_[next_io_context_];
  ++next_io_context_;
  if (next_io_context_ == io_contexts_.size())
    next_io_context_ = 0;
  return io_context;
}

} // namespace server2
} // namespace http

 在run()函数中为每个线程分配了一个io_context;每个线程调用各自的io_context::run函数(类似wait),

当这个io_context上有异步请求时就触发在这个io_context上的run等待,然后去处理这个请求,等请求处理完毕后(比如接收数据完毕)调用请求传入的回调函数进行下一步操作(多数时候是发起新一轮请求)。实际上run线程在等待到请求后,并不能立马处理请求,它需要再次等待请求处理的条件的到来,比如,你发起了一个接收请求,如果这个时候客户端并没有向服务器发送数据,则这个接收请求就会在那里等待,直到客户端有数据发送过来,然后run线程接收完数据再调用你传入的回调函数,通知你请求处理完毕。

connection.hpp 和connection.cpp并无太大的变化,只是去掉了connection_manager相关代码;

main.cpp中调用server对象时需要多传入下参数:线程个数;

三 http::server3 一个io_context多个线程

http::server3的思想是:分配一个共享io_context,让多个线程共同调用io_context::run(),即多个线程共同抢占Io_context任务队列;

与http::server::server相比http::server3::server增加了:线程数 std::size_t thread_pool_size_,去掉了connection_manager; 

核心代码如下:

 1 void server::run()
 2 {
 3   // Create a pool of threads to run all of the io_contexts.
 4   std::vector<boost::shared_ptr<boost::thread> > threads;
 5   for (std::size_t i = 0; i < thread_pool_size_; ++i)
 6   {
 7     boost::shared_ptr<boost::thread> thread(new boost::thread(
 8           boost::bind(&boost::asio::io_context::run, &io_context_)));
 9     threads.push_back(thread);
10   }
11 
12   // Wait for all threads in the pool to exit.
13   for (std::size_t i = 0; i < threads.size(); ++i)
14     threads[i]->join();
15 }
16 
17 void server::start_accept()
18 {
19   new_connection_.reset(new connection(io_context_, request_handler_));
20   acceptor_.async_accept(new_connection_->socket(),
21       boost::bind(&server::handle_accept, this,
22         boost::asio::placeholders::error));
23 }

在run()函数中创建线程,并将每个线程与共享io_context进行绑定;

在start_accept()函数中预先分配一个连接对象,向共享io_context中投递一个等待连接请求,有连接请求到来后调用handlle_accept进行处理,即主线程做监听连接的活;

接下来看connection类

在connection类中增加了

 boost::asio::io_context::strand strand_;来保证异步并发操作能正常有序进行,防止多个线程同时操作一个连接对象,说白了就是让同一个连接上的回调函数执行串行化,所有异步回调操作的地方都需要使用strand_来进行控制

源码如下:
#include "connection.h"

#include    <vector>
#include    <boost/bind.hpp>
#include    "connection_manager.h"
#include    "request_handler.h"

namespace http
{
    namespace server3
    {

        connection::connection(boost::asio::io_context & io_context, 
            request_handler & handler)
            :strand_(io_context),
            socket_(io_context),
            request_handler_(handler)
        {

        }

        boost::asio::ip::tcp::socket& connection::socket()
        {
            return    socket_;
        }

        void connection::start()
        {
            //使用strand来保证对该socket的访问是串行化的
            socket_.async_read_some(boost::asio::buffer(buffer_),
                boost::asio::bind_executor(strand_, 
                    boost::bind(&connection::handle_read, 
                    shared_from_this(), 
                    boost::asio::placeholders::error, 
                    boost::asio::placeholders::bytes_transferred)//end bind
                )//end bind_executor
            );

        }

        void connection::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred)
        {
            if (!e)
            {
                boost::tribool    result;
                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::asio::bind_executor(strand_,
                            boost::bind(&connection::handle_write, shared_from_this(),
                            boost::asio::placeholders::error)//end bin
                        )//end bind_executor
                    );

                }
                else if (!result)
                {
                    reply_ = reply::stock_reply(reply::bad_request);

                    boost::asio::async_write(socket_, reply_.to_buffers(),
                        boost::asio::bind_executor(strand_,
                            boost::bind(&connection::handle_write, shared_from_this(),
                            boost::asio::placeholders::error)//end bind
                        )//end bind_executor
                    );
                }
                else
                {
                    socket_.async_read_some(boost::asio::buffer(buffer_),
                         boost::asio::bind_executor(strand_,
                             boost::bind(&connection::handle_read, shared_from_this(),
                                boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred
                             )//end bind
                         )//end bind_executor
                    );
                }
            }

            //If an error occurs then  no new asynchronous operations are started. This
            //means that all shared_ptr references to the connection object will 
            //disappear and the object will be destroyed automatically after this 
            //handler returns. The connection class's destructor closes the socket.

        }

        void connection::handle_write(const boost::system::error_code& e)
        {
            if (!e)
            {
                boost::system::error_code    ignored_ec;

                socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
            }

            // No new asynchronous operations are started. This means that all shared_ptr
            // references to the connection object will disappear and the object will be
            // destroyed automatically after this handler returns. The connection class's
            // destructor closes the socket.
            
        }

    }//namespace server3
}//namespace http

可以看出所有的async_操作都加上了strand_进行串行化控制;

四 结论
http::server没什么好说的就是一个单线程,这里主要说明http::server2和http::server3的区别

http::server2

思想:为每个线程分配一个io_context,每个线程访问自己相关io_context的任务队列。

优点:每个线程只访问自己的任务队列,不用增加额外的锁相关开销;且保证了一个socket连接只在一个线程中,不会出现两个线程同时访问该socket的情况
缺点:会出现一个线程忙死,另一个线程闲死的情况


http::server3

思想:分配一个共享io_context,让多个线程共同调用io_context::run(),即多个线程共同抢占Io_context任务队列;

优点:每个线程的机会是均等的不会出现一个线程忙死,另一个线程闲死的情况;
缺点:多个线程访问同一个任务队列,增加额外加锁,释放锁的开销;并且因为是多个线程访问同一个任务队列,就会出现两个线程同时等待访问一个socket的情况,

    要么对该socket加锁,要么使用boost::strand来保证串行执行,不管用哪一个都增加额外开销


通过比较发现在serve2中的优点恰是serve3的缺点,serve2的缺点恰是serve3的优点,具体使用哪个方案要看具体的项目,
如果是大量同时登录且登录后操作不多的情况server2更好一点,
如果是传统应用中客户端连接数比较少,且一个客户端要对服务器做大量操作,则server3更适合;


以上纯属个人学习笔记,如有理解不妥之处望高手指正;







猜你喜欢

转载自www.cnblogs.com/guoliushui/p/9055603.html
今日推荐