使用asio和协程实现echo服务器

使用boost asio和有栈协程实现echo服务器,session函数代表连接会话,可以看到session中的对异步完成操作的语法法如同写过程式函数一样简洁明了。和常见写法:用shared_ptr管理对象生存期、在异步操作完成函数中发起新的异步操作相比,很容易理解。

#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/write.hpp>
#include <iostream>
#include <memory>
#include <string_view>

using boost::asio::ip::tcp;

void session(tcp::socket&& socket)
{
  boost::asio::spawn([socket_ = std::move(socket)](boost::asio::yield_context yield) mutable {
    try {
      boost::system::error_code ec;
      char                      data[16];
      for (;;) {
        std::size_t n = socket_.async_read_some(boost::asio::buffer(data), yield[ec]);
        if (!n) {
          break;
        }
        boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield);
      }
    } catch (std::exception& e) {
      socket_.close();
    }
  });
}

int main(int argc, char* argv[])
{
  try {
    int port = 15999;
    if (argc == 2) {
      port = std::atoi(argv[1]);
    }

    boost::asio::io_context io_context;

    boost::asio::spawn(io_context, [&](boost::asio::yield_context yield) {
      tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));

      for (;;) {
        boost::system::error_code ec;
        tcp::socket               socket(io_context);
        acceptor.async_accept(socket, yield[ec]);
        if (!ec) {
          session(std::move(socket));
        }
      }
    });

    io_context.run();
  } catch (std::exception& e) {
    std::cerr << "Exception: " << e.what() << "\n";
  }
  return 0;
}
Posted 2020-10-14