echo_server.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. //
  2. // echo_server.cpp
  3. // ~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #include <boost/asio/io_context.hpp>
  11. #include <boost/asio/ip/tcp.hpp>
  12. #include <boost/asio/spawn.hpp>
  13. #include <boost/asio/steady_timer.hpp>
  14. #include <boost/asio/write.hpp>
  15. #include <iostream>
  16. #include <memory>
  17. using boost::asio::ip::tcp;
  18. class session : public std::enable_shared_from_this<session>
  19. {
  20. public:
  21. explicit session(boost::asio::io_context& io_context, tcp::socket socket)
  22. : socket_(std::move(socket)),
  23. timer_(io_context),
  24. strand_(io_context.get_executor())
  25. {
  26. }
  27. void go()
  28. {
  29. auto self(shared_from_this());
  30. boost::asio::spawn(strand_,
  31. [this, self](boost::asio::yield_context yield)
  32. {
  33. try
  34. {
  35. char data[128];
  36. for (;;)
  37. {
  38. timer_.expires_from_now(std::chrono::seconds(10));
  39. std::size_t n = socket_.async_read_some(boost::asio::buffer(data), yield);
  40. boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield);
  41. }
  42. }
  43. catch (std::exception& e)
  44. {
  45. socket_.close();
  46. timer_.cancel();
  47. }
  48. });
  49. boost::asio::spawn(strand_,
  50. [this, self](boost::asio::yield_context yield)
  51. {
  52. while (socket_.is_open())
  53. {
  54. boost::system::error_code ignored_ec;
  55. timer_.async_wait(yield[ignored_ec]);
  56. if (timer_.expires_from_now() <= std::chrono::seconds(0))
  57. socket_.close();
  58. }
  59. });
  60. }
  61. private:
  62. tcp::socket socket_;
  63. boost::asio::steady_timer timer_;
  64. boost::asio::strand<boost::asio::io_context::executor_type> strand_;
  65. };
  66. int main(int argc, char* argv[])
  67. {
  68. try
  69. {
  70. if (argc != 2)
  71. {
  72. std::cerr << "Usage: echo_server <port>\n";
  73. return 1;
  74. }
  75. boost::asio::io_context io_context;
  76. boost::asio::spawn(io_context,
  77. [&](boost::asio::yield_context yield)
  78. {
  79. tcp::acceptor acceptor(io_context,
  80. tcp::endpoint(tcp::v4(), std::atoi(argv[1])));
  81. for (;;)
  82. {
  83. boost::system::error_code ec;
  84. tcp::socket socket(io_context);
  85. acceptor.async_accept(socket, yield[ec]);
  86. if (!ec)
  87. {
  88. std::make_shared<session>(io_context, std::move(socket))->go();
  89. }
  90. }
  91. });
  92. io_context.run();
  93. }
  94. catch (std::exception& e)
  95. {
  96. std::cerr << "Exception: " << e.what() << "\n";
  97. }
  98. return 0;
  99. }