echo_server.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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 <boost/bind.hpp>
  16. #include <boost/shared_ptr.hpp>
  17. #include <boost/enable_shared_from_this.hpp>
  18. #include <iostream>
  19. using boost::asio::ip::tcp;
  20. class session : public boost::enable_shared_from_this<session>
  21. {
  22. public:
  23. explicit session(boost::asio::io_context& io_context)
  24. : strand_(boost::asio::make_strand(io_context)),
  25. socket_(io_context),
  26. timer_(io_context)
  27. {
  28. }
  29. tcp::socket& socket()
  30. {
  31. return socket_;
  32. }
  33. void go()
  34. {
  35. boost::asio::spawn(strand_,
  36. boost::bind(&session::echo,
  37. shared_from_this(), _1));
  38. boost::asio::spawn(strand_,
  39. boost::bind(&session::timeout,
  40. shared_from_this(), _1));
  41. }
  42. private:
  43. void echo(boost::asio::yield_context yield)
  44. {
  45. try
  46. {
  47. char data[128];
  48. for (;;)
  49. {
  50. timer_.expires_after(boost::asio::chrono::seconds(10));
  51. std::size_t n = socket_.async_read_some(boost::asio::buffer(data), yield);
  52. boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield);
  53. }
  54. }
  55. catch (std::exception& e)
  56. {
  57. socket_.close();
  58. timer_.cancel();
  59. }
  60. }
  61. void timeout(boost::asio::yield_context yield)
  62. {
  63. while (socket_.is_open())
  64. {
  65. boost::system::error_code ignored_ec;
  66. timer_.async_wait(yield[ignored_ec]);
  67. if (timer_.expiry() <= boost::asio::steady_timer::clock_type::now())
  68. socket_.close();
  69. }
  70. }
  71. boost::asio::strand<boost::asio::io_context::executor_type> strand_;
  72. tcp::socket socket_;
  73. boost::asio::steady_timer timer_;
  74. };
  75. void do_accept(boost::asio::io_context& io_context,
  76. unsigned short port, boost::asio::yield_context yield)
  77. {
  78. tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));
  79. for (;;)
  80. {
  81. boost::system::error_code ec;
  82. boost::shared_ptr<session> new_session(new session(io_context));
  83. acceptor.async_accept(new_session->socket(), yield[ec]);
  84. if (!ec) new_session->go();
  85. }
  86. }
  87. int main(int argc, char* argv[])
  88. {
  89. try
  90. {
  91. if (argc != 2)
  92. {
  93. std::cerr << "Usage: echo_server <port>\n";
  94. return 1;
  95. }
  96. boost::asio::io_context io_context;
  97. boost::asio::spawn(io_context,
  98. boost::bind(do_accept,
  99. boost::ref(io_context), atoi(argv[1]), _1));
  100. io_context.run();
  101. }
  102. catch (std::exception& e)
  103. {
  104. std::cerr << "Exception: " << e.what() << "\n";
  105. }
  106. return 0;
  107. }