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更適合;


以上純屬個人學習筆記,如有理解不妥之處望高手指正;


 

 







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM