-BOOST ASIO- async_tcp_echo_server VSblocking_tcp_echo_server

问题描述 投票:0回答:1

我正在研究BOOST ASIO。 https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/examples/cpp14_examples.html

这里有一些例子。

查看blocking_tcp_echo_server, 该示例使用线程作为处理多个客户端的方法。 我的问题是与 async_tcp_echo_server 示例是否有任何功能差异。

blocking_tcp_echo_server

#include <cstdlib>
#include <iostream>
#include <thread>
#include <utility>
#include <boost/asio.hpp>

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

const int max_length = 1024;

void session(tcp::socket sock)
{
  try
  {
    for (;;)
    {
      char data[max_length];

      boost::system::error_code error;
      size_t length = sock.read_some(boost::asio::buffer(data), error);
      if (error == boost::asio::error::eof)
        break; // Connection closed cleanly by peer.
      else if (error)
        throw boost::system::system_error(error); // Some other error.

      boost::asio::write(sock, boost::asio::buffer(data, length));
    }
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception in thread: " << e.what() << "\n";
  }
}

void server(boost::asio::io_context& io_context, unsigned short port)
{
  tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), port));
  for (;;)
  {
    std::thread(session, a.accept()).detach();
  }
}

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

    boost::asio::io_context io_context;

    server(io_context, std::atoi(argv[1]));
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << "\n";
  }

  return 0;
}

async_tcp_echo_server

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <boost/asio/ts/buffer.hpp>
#include <boost/asio/ts/internet.hpp>

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

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

  void start()
  {
    do_read();
  }

private:
  void do_read()
  {
    auto self(shared_from_this());
    socket_.async_read_some(boost::asio::buffer(data_, max_length),
        [this, self](boost::system::error_code ec, std::size_t length)
        {
          if (!ec)
          {
            do_write(length);
          }
        });
  }

  void do_write(std::size_t length)
  {
    auto self(shared_from_this());
    boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            do_read();
          }
        });
  }

  tcp::socket socket_;
  enum { max_length = 1024 };
  char data_[max_length];
};

class server
{
public:
  server(boost::asio::io_context& io_context, short port)
    : acceptor_(io_context, tcp::endpoint(tcp::v4(), port)),
      socket_(io_context)
  {
    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();
        });
  }

  tcp::acceptor acceptor_;
  tcp::socket socket_;
};

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

    boost::asio::io_context io_context;

    server s(io_context, std::atoi(argv[1]));

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

  return 0;
}
c++ boost-asio
1个回答
0
投票

除了错误报告方面非常轻微(且非常明显)的差异之外,两者之间没有功能差异。

这里的差异最小化,在一个可以运行阻塞和同步的程序中重用尽可能多的代码:

住在Coliru

#include <boost/asio.hpp>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <utility>

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

static constexpr auto max_length = 1024;

namespace blocking {
    void session(tcp::socket sock) try {
        char data[max_length];
        for (error_code ec; size_t length = sock.read_some(asio::buffer(data), ec);) {
            if (ec == asio::error::eof)
                break; // Connection closed cleanly by peer.
            if (ec)
                throw boost::system::system_error(ec); // Some other error.

            write(sock, asio::buffer(data, length));
        }
    } catch (std::exception const& e) {
        std::cerr << "Exception in thread: " << e.what() << "\n";
    }

    void server(asio::io_context& io_context, uint16_t port) {
        for (tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), port));;)
            std::thread(session, a.accept()).detach();
    }
} // namespace blocking

namespace async {
    struct session : std::enable_shared_from_this<session> {
        session(tcp::socket socket) : socket_(std::move(socket)) {}
        void start() { do_read(); }

      private:
        void do_read() {
            socket_.async_read_some( //
                asio::buffer(data_), [this, self = shared_from_this()](error_code ec, size_t length) {
                    if (!ec)
                        do_write(length);
                });
        }

        void do_write(size_t length) {
            async_write( //
                socket_, asio::buffer(data_, length),
                [this, self = shared_from_this()](error_code ec, size_t /*length*/) {
                    if (!ec)
                        do_read();
                });
        }

        tcp::socket socket_;
        char data_[max_length];
    };

    struct server {
        server(asio::io_context& io_context, uint16_t port) : acceptor_(io_context, {{}, port}) {
            do_accept();
        }

      private:
        void do_accept() {
            acceptor_.async_accept([this](error_code ec, tcp::socket s) {
                if (!ec)
                    std::make_shared<session>(std::move(s))->start();

                do_accept();
            });
        }

        tcp::acceptor acceptor_;
    };
} // namespace async

#include <ranges>
int main(int argc, char** argv) try {
    std::vector<std::string_view> args(argv + 1, argv + argc);

    bool async = false;
    if (auto it = std::ranges::find(args, "async"); it != end(args)) {
        args.erase(it);
        async = true;
    }

    uint16_t port = static_cast<uint16_t>(std::atoi(args.at(0).data()));
    asio::io_context ioc;

    if (async) {
        async::server srv(ioc, port);
        ioc.run();
    } else {
        blocking::server(ioc, port);
    }
} catch (std::exception const& e) {
    std::cerr << "Exception: " << e.what() << "\n";
}

当然,技术差异包括异步服务器不会创建额外的线程。

© www.soinside.com 2019 - 2024. All rights reserved.