实施异步TCP服务器

以下内容摘自《Boost.Asio C++ Network Programming Cookbook》

异步TCP服务器是满足以下条件的分布式应用程序的一部分:

  • 在客户端-服务器通信模型(c/s模型)中充当服务器
  • 通过TCP协议与客户端应用程序通信
  • 使用异步I / O和控制操作
  • 可以同时处理多个客户

典型的异步TCP服务器根据以下算法工作:

  1. 分配一个接受套接字(acceptor socket),并将其绑定到特定的TCP端口。
  2. 启动异步接受操作。
  3. 生成一个或多个控制线程,并将其添加到运行Boost.Asio事件循环的线程池中。
  4. 异步接受操作完成后,启动一个新的操作以接受下一个连接请求。
  5. 启动异步读取操作以从连接的客户端读取请求。
  6. 异步读取操作完成后,处理请求并准备响应消息。
  7. 启动异步写入操作以将响应消息发送到客户端。
  8. 异步写入操作完成后,关闭连接并解除分配的套接字。

代码实现:
包含三个类:

  • Service: 处理接受消息,并发送响应消息。
  • Acceptor: 监听客户端请求连接, 并创建Service对象为客户端提供服务。
  • Server: 服务器本身
#include 
#include 
#include 
#include 
#include 

using namespace boost;
 // 定义一个负责处理单个客户端的类,该类通过读取请求消息,对其进行处理然后向客户端发送响应消息来进行。 
 // 此类表示服务器应用程序提供的单个服务。 我们将其命名为Service:
class Service
{
public:
    Service(std::shared_ptr sock) : m_sock(sock) {}
    void StartHandling()
    {
        asio::async_read_until(*m_sock.get(),
            m_request,
            '\n',
            [this](const boost::system::error_code& ec,
                std::size_t bytes_transferred) {
                onRequestReceived(ec, bytes_transferred);});
    }

private:
    void onRequestReceived(const boost::system::error_code& ec, std::size_t bytes_transferred)
    {
        if (ec.value() != 0) {
            std::cout << "Error occured! Error code = "
                << ec.value()
                << ". Message: " << ec.message();

            onFinish();
            return;
        }
        // 处理请求
        m_response = ProcessRequest(m_request);

        //启动异步写操作
        asio::async_write(*m_sock.get(),
            asio::buffer(m_response),
            [this](const boost::system::error_code& ec,
                std::size_t bytes_transferred)
            {
            onResponseSent(ec, bytes_transferred);
            }
        );
    }

    // 解析请求,进行处理,return回应消息
    std::string ProcessRequest(asio::streambuf& request) 
    {
        // 模拟消耗CPU的操作
        int i = 0;
        while (i != 1000000)
            i++;

        // 模拟阻塞线程的操作,比如,同步IO操作
        std::this_thread::sleep_for(
            std::chrono::milliseconds(100));

        // return 回应消息
        std::string response = "Response\n";
        return response;
    }

    void onResponseSent(const boost::system::error_code& ec,
        std::size_t bytes_transferred) 
    {
        if (ec.value() != 0) {
            std::cout << "Error occured! Error code = "
                << ec.value()
                << ". Message: " << ec.message();
        }
        onFinish();
    }

    void onFinish()
    {
        delete this;
    }

    std::shared_ptr m_sock;
    std::string m_response;
    asio::streambuf m_request;
};

// 该类代表一个 high-level acceptor 概念(与asio::ip::tcp::acceptor类所代表的low-level概念相比)
// 此类负责接受来自客户端的连接请求,并实例化Service类的对象,该类将向连接的客户端提供服务。
class Acceptor
{
public:
    Acceptor(asio::io_service& ios, unsigned short port_num) :
        m_ios(ios),
        m_acceptor(m_ios,
            asio::ip::tcp::endpoint(asio::ip::tcp::endpoint(
                asio::ip::address_v4::any(),
                port_num))),
        m_isStopped(false)
    {}
    // 开始接受传入的连接请求
    void Start()
    {
        m_acceptor.listen();
        InitAccept();
    }
    // 停止接受传入的连接请求
    void Stop() {
        m_isStopped.store(true);
    }
private:
    void InitAccept() 
    {
        std::shared_ptr
            sock(new asio::ip::tcp::socket(m_ios));

        m_acceptor.async_accept(*sock.get(),
            [this, sock](
                const boost::system::error_code& error)
        {
            onAccept(error, sock);
        });
    }

    void onAccept(const boost::system::error_code& ec,
        std::shared_ptr sock)
    {
        if (ec.value() == 0) {
            (new Service(sock))->StartHandling();
        }
        else {
            std::cout << "Error occured! Error code = "
                << ec.value()
                << ". Message: " << ec.message();
        }

        // Init next async accept operation if
        // acceptor has not been stopped yet.
        if (!m_isStopped.load()) {
            InitAccept();
        }
        else {
            // Stop accepting incoming connections
            // and free allocated resources.
            m_acceptor.close();
        }
    }

    asio::io_service& m_ios;
    asio::ip::tcp::acceptor m_acceptor;
    std::atomic m_isStopped;
};

// 该类代表服务器本身
class Server
{
public:
    Server()
    {
        m_work.reset(new asio::io_service::work(m_ios));
    }

    void Start(unsigned short port_num, unsigned int thread_pool_size)
    {
        assert(thread_pool_size > 0);
        acc.reset(new Acceptor(m_ios, port_num));
        acc->Start();
        // 创建具体数量的线程,并将其加入到线程池
        for (unsigned int i = 0; i < thread_pool_size; i++) {
            std::unique_ptr th(
                new std::thread([this]() 
                {
                    // The run() function blocks until all work has finished and there are no more handlers to be dispatched, 
                    // or until the io_context has been stopped.

                    // Multiple threads may call the run() function to set up a pool of threads from which the io_context may execute handlers. 
                    // All threads that are waiting in the pool are equivalent 
                    // and the io_context may choose any one of them to invoke a handler.
                    
                    // A normal exit from the run() function implies that the io_context object is stopped (the stopped() function returns true). 
                    // Subsequent calls to run(), run_one(), poll() or poll_one() will return immediately unless there is a prior call to restart().

                    // Calling the run() function from a thread that is currently calling one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on the same io_context object may introduce the potential for deadlock. 
                    // It is the caller's reponsibility to avoid this.
                    
                    // 从以上解释中,可以推断,可以在不同线程中调用run(),但是不可以在同一个线程中多次调用run(),
                    m_ios.run(); 
                }));
            m_thread_pool.push_back(std::move(th));
        }
    }

    void Stop()
    {
        acc->Stop();
        m_ios.stop();

        for (auto& th : m_thread_pool) {
            th->join();
        }
    }
private:
    asio::io_service m_ios;
    std::unique_ptr m_work;
    std::unique_ptr acc;
    std::vector> m_thread_pool;
};

const unsigned int DEFAULT_THREAD_POOL_SIZE = 2;
int main()
{
    unsigned short port_num = 3333;
    try {
        Server srv;
        // use the std::thread::hardware_concurrency() static method to obtain the number of processors. 
        // However, because this method may fail to do its job returning 0, 
        // we fall back to default value represented by the constant DEFAULT_THREAD_POOL_SIZE, 
        // which is equal to 2 in our case.
        unsigned int thread_pool_size =
            std::thread::hardware_concurrency() * 2;

        if (thread_pool_size == 0)
            thread_pool_size = DEFAULT_THREAD_POOL_SIZE;

        srv.Start(port_num, thread_pool_size);
        std::this_thread::sleep_for(std::chrono::seconds(60));
        srv.Stop();
    }
    catch (system::system_error& e) {
        std::cout << "Error occured! Error code = "
            << e.code() << ". Message: "
            << e.what();
    }
    return 0;
}

你可能感兴趣的:(实施异步TCP服务器)