Boost: ASIO connection management 9

Source: Internet
Author: User

This section first refactor the code. The business logic code and the communication infrastructure code need to be decoupled. The business logic code processes the protocols in the communication process and the application logic behind them. Communication Infrastructure Code focuses on concurrency, TCP connection, and other features.

First, some member functions of connection in the previous Code are purely virtual functions. The business class can inherit them and rewrite the virtual functions as needed.

The server programming template class accepts the business class as the template parameter, as long as the class provides several required public member functions.

Therefore, the directory structure is adjusted as follows:

├── CMakeLists.txt├── include│   ├── business│   └── core└── src    ├── business    ├── CMakeLists.txt    ├── core    └── main.cc

Server class because it is a template class, delete the. CC file, only keep the. h file, and put it in the core directory.

The connection class is also stored in the core directory and also changed to a template class. These two classes under core are the communication basic classification class.

Create a new business class with application logic-related code. Now there is a client class.

Modify the src/cmakelists.txt file as follows:

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)AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/business CPP_LIST3)add_executable(service ${CPP_LIST1} ${CPP_LIST2} ${CPP_LIST3})target_link_libraries(service ${Boost_LIBRARIES})add_definitions(-Wall)

Okay. Now let's take a look at the main. CC code:

#include <iostream>#include "core/server.h"#include "business/client.h"using namespace std;int main(int argc,char ** argv) {    try {io_service iosev;tcp::endpoint listen_endpoint(tcp::v4(), 8888);        Server<Client> server(iosev, listen_endpoint, 10);        server.Run();    } catch(std::exception const& ex) {      cout << "Exception: " << ex.what() << "";    }}

The change is to include client. h file and create the server <client> object.

Take a look at the core/server. h file:

#ifndef CORE_SERVER_H_#define CORE_SERVER_H_#include <boost/asio.hpp>#include <boost/bind.hpp>#include <boost/thread/thread.hpp>#include <vector>using namespace std;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// You should provide your class as template argument here// Your class must inherit from Connection class.template<class T>class Server { public:  typedef T ClientType; 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<ClientType> c(new ClientType(io_));                acceptor_.async_accept(c->socket, bind(&Server::AfterAccept, this, c, _1));    }  void AfterAccept(shared_ptr<ClientType>& 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<ClientType> c2(new ClientType(io_));      acceptor_.async_accept(c2->socket, bind(&Server::AfterAccept, this, c2, _1));    }  }  // Create a thread pool for io_service  // Launch io_service  void 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();    }  } private:  void Stop() {    cout << "stopping" << endl;    acceptor_.close();    io_.stop();  } private:  io_service& io_;  boost::asio::signal_set signals_;  tcp::acceptor acceptor_;  size_t thread_pool_size_;};#endif

Let's look at the connection. h file again:

#ifndef CORE_CONNECTION_H_#defineCORE_CONNECTION_H_#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;template<class T>class Connection: public boost::enable_shared_from_this<T> { public: Connection(io_service& s)   : socket(s), strand_(s) {  }  ~Connection() {  }  // You must override it yourself  // Default implementation closes the socket using shutdonw&cloes methods  // You could override it if want change it  // Or resue it with Connection::CloseSocket() format  void CloseSocket() {    socket.shutdown(tcp::socket::shutdown_both);    socket.close();  }      // You must override it yourself  virtual void StartJob() = 0;  tcp::socket socket;      // Strand to ensure the connection's handlers are not called concurrently.  boost::asio::io_service::strand strand_;};#endif

There are two changes:

1. added the keyword virtual... = 0

2. The template parameter of enable_shared_from_this is t instead of the connection class.

Now let's look at business/client. H. This class implements the logic for communication between a specific server and a client.

#ifndef BUSINESS_CLIENT_H_#define BUSINESS_CLIENT_H_#include "core/connection.h"#include <vector>using namespace std;class Client: public Connection<Client> { public:  Client(io_service& s);  void StartJob();  void CloseSocket();  void AfterReadChar(error_code const& ec); private:  vector<char> read_buffer_;};#endif

Client. CC file code:

#include "business/client.h"#include <boost/bind.hpp>using namespace boost;Client::Client(io_service& s):  Connection(s), read_buffer_(1, 0) {}void Client::StartJob() {    async_read(socket, buffer(read_buffer_),       strand_.wrap(bind(&Client::AfterReadChar, shared_from_this(), _1)));}void Client::CloseSocket() {  Connection::CloseSocket();}void Client::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(&Client::AfterReadChar, shared_from_this(), _1)));    } else {        cout << "wrong data received, char is:" << (int) x << endl;        CloseSocket();    }}

Now, this decoupling is enough. Test in the next section.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.