boost::asio 连接管理8

转自:http://blog.csdn.net/sheismylife/article/details/8509611

 

到上一篇,一个完整的单线程版本就出现了。如果并发要求不高的话,单线程+异步I/O已经足够了。

但是如果想支持大并发,自然需要尽可能的利用服务器上的多个CPU和核。

现在首先把之前的工程改成cmake工程。

顶层目录的CMakeLists.txt内容如下:

  1. cmake_minimum_required(VERSION 2.8)  
  2. project (TcpTemplate)  
  3. add_subdirectory(src bin)  
cmake_minimum_required(VERSION 2.8)
project (TcpTemplate)
add_subdirectory(src bin)


src目录下的CMakeLists.txt文件配置:

  1. cmake_minimum_required(VERSION 2.8)  
  2. set(CMAKE_BUILD_TYPE Debug)  
  3. set(PROJECT_INCLUDE_DIR ../include)  
  4.   
  5. find_package(Boost COMPONENTS system filesystem thread REQUIRED)  
  6. include_directories(${Boost_INCLUDE_DIR} ${PROJECT_INCLUDE_DIR})  
  7. AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src CPP_LIST1)  
  8. AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/core CPP_LIST2)  
  9.   
  10. add_executable(service ${CPP_LIST1} ${CPP_LIST2})  
  11. target_link_libraries(service ${Boost_LIBRARIES})  
  12.   
  13. add_definitions(-Wall)  
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)
set(PROJECT_INCLUDE_DIR ../include)

find_package(Boost COMPONENTS system filesystem thread REQUIRED)
include_directories(${Boost_INCLUDE_DIR} ${PROJECT_INCLUDE_DIR})
AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src CPP_LIST1)
AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/core CPP_LIST2)

add_executable(service ${CPP_LIST1} ${CPP_LIST2})
target_link_libraries(service ${Boost_LIBRARIES})

add_definitions(-Wall)


好,现在看一下main.cc,没有什么太大变化,只是把Server类的代码剥离出去了。

  1. #include <iostream>   
  2. #include "core/server.h"   
  3.   
  4. using namespace std;  
  5.   
  6. int main(int argc,char ** argv) {  
  7.     try {  
  8.     io_service iosev;  
  9.     tcp::endpoint listen_endpoint(tcp::v4(), 8888);  
  10.         Server server(iosev, listen_endpoint, 10);  
  11.         server.Run();  
  12.     } catch(std::exception const& ex) {  
  13.       cout << "Exception: " << ex.what() << "";  
  14.     }  
  15. }  
#include <iostream>
#include "core/server.h"

using namespace std;

int main(int argc,char ** argv) {
    try {
	io_service iosev;
	tcp::endpoint listen_endpoint(tcp::v4(), 8888);
        Server server(iosev, listen_endpoint, 10);
        server.Run();
    } catch(std::exception const& ex) {
      cout << "Exception: " << ex.what() << "";
    }
}

Server类和Connection类都放在core目录下。注意,这里为了效率,取消了Connetions类统一管理所有的connection,每个connection要么自己主动关闭连接,要么会因为io_service.stop的调用而关闭所有连接。

server.h文件代码:

  1. #ifndef CORE_SERVER_H_  
  2. #define CORE_SERVER_H_  
  3.   
  4. #include <boost/asio.hpp>  
  5. #include "core/connection.h"  
  6.   
  7. using namespace boost;  
  8. using boost::system::error_code;  
  9. using namespace boost::asio;  
  10. using ip::tcp;  
  11.   
  12.   
  13. // Crate a thread pool for io_service  
  14. // Run the io_service to accept new incoming TCP connection and handle the I/O events  
  15. class Server {  
  16.  public:  
  17.   Server(io_service& io_service, tcp::endpoint const& listen_endpoint, size_t threads_number);  
  18.   
  19.   // Create a thread pool for io_service  
  20.   // Launch io_service  
  21.   void Run();  
  22.   
  23.   void AfterAccept(shared_ptr<Connection>& connection, error_code const& ec);  
  24.   
  25.  private:  
  26.   void Stop();  
  27.   
  28.  private:  
  29.   io_service& io_;  
  30.   boost::asio::signal_set signals_;  
  31.   tcp::acceptor acceptor_;  
  32.   size_t thread_pool_size_;  
  33. };  
  34.   
  35. #endif  
#ifndef CORE_SERVER_H_
#define CORE_SERVER_H_

#include <boost/asio.hpp>
#include "core/connection.h"

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


// Crate a thread pool for io_service
// Run the io_service to accept new incoming TCP connection and handle the I/O events
class Server {
 public:
  Server(io_service& io_service, tcp::endpoint const& listen_endpoint, size_t threads_number);

  // Create a thread pool for io_service
  // Launch io_service
  void Run();

  void AfterAccept(shared_ptr<Connection>& connection, error_code const& ec);

 private:
  void Stop();

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

#endif


server.cc文件内容:

  1. #include "core/server.h"   
  2. #include <boost/bind.hpp>   
  3. #include <boost/thread/thread.hpp>   
  4. #include <vector>   
  5. #include "core/connection.h"   
  6.   
  7. using namespace boost;  
  8.   
  9. Server::Server(io_service& s, tcp::endpoint const& listen_endpoint, size_t threads_number)  
  10.   : io_(s),  
  11.     signals_(s),  
  12.     acceptor_(io_, listen_endpoint),  
  13.     thread_pool_size_(threads_number) {  
  14.   signals_.add(SIGINT);  
  15.   signals_.add(SIGTERM);  
  16. #if defined(SIGQUIT)   
  17.   signals_.add(SIGQUIT);  
  18. #endif   
  19.   signals_.async_wait(bind(&Server::Stop, this));  
  20.   shared_ptr<Connection> c(new Connection(io_));  
  21.             
  22.   acceptor_.async_accept(c->socket, bind(&Server::AfterAccept, this, c, _1));  
  23.     }  
  24.   
  25. void Server::AfterAccept(shared_ptr<Connection>& c, error_code const& ec) {  
  26.   // Check whether the server was stopped by a signal before this completion   
  27.   // handler had a chance to run.   
  28.   if (!acceptor_.is_open()) {  
  29.     cout << "acceptor is closed" << endl;  
  30.     return;  
  31.   }  
  32.           
  33.   if (!ec) {  
  34.     c->StartJob();  
  35.     shared_ptr<Connection> c2(new Connection(io_));  
  36.     acceptor_.async_accept(c2->socket,  
  37.                boost::bind(&Server::AfterAccept, this, c2, _1));  
  38.   }  
  39. }  
  40.   
  41. void Server::Run() {  
  42.   // Create a pool of threads to run all of the io_services.   
  43.   vector<shared_ptr<thread> > threads;  
  44.   for (size_t i = 0; i < thread_pool_size_; ++i) {  
  45.     shared_ptr<thread> t(new thread(bind(&io_service::run, &io_)));  
  46.     threads.push_back(t);  
  47.   }  
  48.   
  49.   // Wait for all threads in the pool to exit.   
  50.   for (std::size_t i = 0; i < threads.size(); ++i) {  
  51.     threads[i]->join();  
  52.   }  
  53. }  
  54.   
  55. void Server::Stop() {  
  56.   cout << "stopping" << endl;  
  57.   acceptor_.close();  
  58.   io_.stop();  
  59. }  
#include "core/server.h"
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
#include <vector>
#include "core/connection.h"

using namespace boost;

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

void Server::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()) {
    cout << "acceptor is closed" << endl;
    return;
  }
        
  if (!ec) {
    c->StartJob();
    shared_ptr<Connection> c2(new Connection(io_));
    acceptor_.async_accept(c2->socket,
			   boost::bind(&Server::AfterAccept, this, c2, _1));
  }
}

void Server::Run() {
  // Create a pool of threads to run all of the io_services.
  vector<shared_ptr<thread> > threads;
  for (size_t i = 0; i < thread_pool_size_; ++i) {
    shared_ptr<thread> t(new thread(bind(&io_service::run, &io_)));
    threads.push_back(t);
  }

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

void Server::Stop() {
  cout << "stopping" << endl;
  acceptor_.close();
  io_.stop();
}


Run的实现变复杂了,改成了创建一个线程池,线程都绑定了io_service::run,也就意味着线程都会运行这个函数,直到io_service因为被关闭才会退出。

然后主线程会一直等待,直到所有线程都退出,自己才退出。

而Stop函数被简化了,因为没有了Connections类。


再来看Connection类的实现,connection.h文件内容:

  1. #ifndef CORE_CONNECTION_H_   
  2. #define CORE_CONNECTION_H_   
  3.   
  4. #include <set>   
  5. #include <algorithm>   
  6. #include <vector>   
  7. #include <boost/asio.hpp>   
  8. #include <boost/enable_shared_from_this.hpp>   
  9.   
  10. using namespace boost::asio;  
  11. using ip::tcp;  
  12. using boost::system::error_code;  
  13.   
  14. using namespace boost;  
  15. using namespace std;  
  16.   
  17. class Connection: public boost::enable_shared_from_this<Connection> {  
  18. public:  
  19.     Connection(io_service& s);  
  20.       
  21.     ~Connection();  
  22.       
  23.     void StartJob();  
  24.       
  25.     void CloseSocket();  
  26.       
  27.     void AfterReadChar(error_code const& ec);  
  28.       
  29. public:  
  30.     tcp::socket socket;  
  31.       
  32. private:  
  33.     vector<char> read_buffer_;  
  34.     /// Strand to ensure the connection's handlers are not called concurrently.   
  35.     boost::asio::io_service::strand strand_;  
  36. };  
  37.   
  38.   
  39. #endif  
#ifndef CORE_CONNECTION_H_
#define	CORE_CONNECTION_H_

#include <set>
#include <algorithm>
#include <vector>
#include <boost/asio.hpp>
#include <boost/enable_shared_from_this.hpp>

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

using namespace boost;
using namespace std;

class Connection: public boost::enable_shared_from_this<Connection> {
public:
    Connection(io_service& s);
    
    ~Connection();
    
    void StartJob();
    
    void CloseSocket();
    
    void AfterReadChar(error_code const& ec);
    
public:
    tcp::socket socket;
    
private:
    vector<char> read_buffer_;
    /// Strand to ensure the connection's handlers are not called concurrently.
    boost::asio::io_service::strand strand_;
};


#endif


这里关键是多了一个strand_成员。解释一下:

刚才server创建了一个线程池,池中每个线程都调用了io_service::run方法。按照boost::asio的原则,这些线程都拥有平等的机会来调用connection中的异步I/O处理函数,也就是我的After...函数。由于这是个多线程环境,connection的有效的异步I/O处理函数(一个或者多个)可能会同时被几个线程调用。为了防止出现状态不一致,strand提供了一种承诺,如果我们的bind交由它打一次包,再传递给io_service,则这些回调会保证同一时间点仅有一个线程调用,也就是被用一根绳子(一个strand对象)按照时间顺序串起来了。


connection.cc代码:

  1. #include "core/connection.h"   
  2. #include <boost/bind.hpp>   
  3.   
  4. Connection::Connection(io_service& s)  
  5.   : socket(s), read_buffer_(1, 0), strand_(s) {  
  6.   
  7. }  
  8.   
  9. Connection::~Connection() {  
  10.     cout << "~Connection" << endl;  
  11. }  
  12.   
  13. void Connection::StartJob() {  
  14.     cout << "the new connection object is starting now." << endl;  
  15.     async_read(socket, buffer(read_buffer_),  
  16.            strand_.wrap(bind(&Connection::AfterReadChar, shared_from_this(), _1)));  
  17. }  
  18.   
  19. void Connection::CloseSocket() {  
  20.     cout << "closing the socket" << endl;  
  21.     socket.shutdown(tcp::socket::shutdown_both);  
  22.     socket.close();  
  23. }  
  24.   
  25. void Connection::AfterReadChar(error_code const& ec) {  
  26.     if (ec) {  
  27.         cout << ec.message() << endl;  
  28.         return;  
  29.     }  
  30.   
  31.     char x = read_buffer_[0];  
  32.     if (x == 'a') {  
  33.         cout << "correct data received" << endl;  
  34.         async_read(socket, buffer(read_buffer_),  
  35.            strand_.wrap(bind(&Connection::AfterReadChar, shared_from_this(), _1)));  
  36.     } else {  
  37.         cout << "wrong data received, char is:" << (int) x << endl;  
  38.         CloseSocket();  
  39.     }  
  40. }  
#include "core/connection.h"
#include <boost/bind.hpp>

Connection::Connection(io_service& s)
  : socket(s), read_buffer_(1, 0), strand_(s) {

}

Connection::~Connection() {
    cout << "~Connection" << endl;
}

void Connection::StartJob() {
    cout << "the new connection object is starting now." << endl;
    async_read(socket, buffer(read_buffer_),
	       strand_.wrap(bind(&Connection::AfterReadChar, shared_from_this(), _1)));
}

void Connection::CloseSocket() {
    cout << "closing the socket" << endl;
    socket.shutdown(tcp::socket::shutdown_both);
    socket.close();
}

void Connection::AfterReadChar(error_code const& ec) {
    if (ec) {
        cout << ec.message() << endl;
        return;
    }

    char x = read_buffer_[0];
    if (x == 'a') {
        cout << "correct data received" << endl;
        async_read(socket, buffer(read_buffer_),
		   strand_.wrap(bind(&Connection::AfterReadChar, shared_from_this(), _1)));
    } else {
        cout << "wrong data received, char is:" << (int) x << endl;
        CloseSocket();
    }
}


好了,目前实现了线程池并发,并且保证了单个Connection对象的调用的线性化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值