很多使用boost::asio的同学觉得asio网络库写网络程序的时候,逻辑上很难理解,boost 1.53中asio带了一个coro类。asio::coro是协程的状态机实现,使用asio::coro可以用同步的逻辑写一步的代码,简化代码逻辑。

#include <boost/asio.hpp>
#include <iostream>
#include <memory>
#include <utility>
#include <vector>
#include <boost/asio/yield.hpp>
#include <boost/bind.hpp>

class shared_const_buffer
{
public:
  // Construct from a std::string.
  explicit shared_const_buffer(const std::string& data)
    : data_(new std::vector<char>(data.begin(), data.end())),
      buffer_(boost::asio::buffer(*data_))
  {
  }

  // Implement the ConstBufferSequence requirements.
  typedef boost::asio::const_buffer value_type;
  typedef const boost::asio::const_buffer* const_iterator;
  const boost::asio::const_buffer* begin() const { return &buffer_; }
  const boost::asio::const_buffer* end() const { return &buffer_ + 1; }

private:
  std::shared_ptr<std::vector<char> > data_;
  boost::asio::const_buffer buffer_;
};

class session
  : public std::enable_shared_from_this<session>
{
public:
  session(boost::asio::ip::tcp::socket socket)
    : socket_(std::move(socket))
  {
  }

  ~session()
  {
    socket_.close();
  }

  void start()
  {
    handler_process(boost::system::error_code(),0);
  }

  void handler_process(boost::system::error_code ec, size_t bytes_transferred)
  {
    std::time_t now = std::time(0);
    shared_const_buffer buffer(std::ctime(&now));

    if (ec)
    {
      return;
    }

    std::istream request_stream(&request_);
    std::string recv_line;

    reenter (&coro_) for (;;)
    {
      yield boost::asio::async_read_until(socket_, request_, "\r\n",
        boost::bind(&session::handler_process, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));

      std::getline(request_stream, recv_line);
      if(recv_line.substr(0, 4) == "time")
      {
        yield boost::asio::async_write(socket_, buffer, 
          boost::bind(&session::handler_process, shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
      }
      else if(recv_line.substr(0, 4) == "quit")
      {
        return;  
      }
    }
  }

private:
  // The socket used to communicate with the client.
  boost::asio::ip::tcp::socket socket_;

  boost::asio::coroutine coro_;

   boost::asio::streambuf request_;
};

class server
{
public:
  server(boost::asio::io_service& io_service, short port)
    : acceptor_(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
      socket_(io_service)
  {
    do_accept();
  }

private:
  void do_accept()
  {
    acceptor_.async_accept(socket_,
        [this](boost::system::error_code ec)
        {
          if (!ec)
          {
            std::make_shared<session>(std::move(socket_))->start();
          }

          do_accept();
        });
  }

  boost::asio::ip::tcp::acceptor acceptor_;
  boost::asio::ip::tcp::socket socket_;
};

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: coro <port>\n";
      return 1;
    }

    boost::asio::io_service io_service;

    server s(io_service, std::atoi(argv[1]));
    
    std::cout << "started on tcp://127.0.0.1:" << argv[1] << "; press Ctrl-C to terminate." << std::endl;   

    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

编译命令:

gcc -o coro coro.cc -lstdc++ -lboost_system --std=c++0x

运行terminal1:

./coro 8001

运行terminal2:

telnet localhost 8001

结果:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Thu Sep 12 20:53:10 2013
Thu Sep 12 20:53:10 2013
Connection closed by foreign host.