client.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. //
  2. // client.hpp
  3. // ~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 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. #ifndef CHAT_CLIENT_HPP
  11. #define CHAT_CLIENT_HPP
  12. #include <deque>
  13. #include "asio.hpp"
  14. #include "chat_message.hpp"
  15. typedef std::deque<chat_message> chat_message_queue;
  16. class chat_client
  17. {
  18. public:
  19. chat_client(asio::io_context& io_context,
  20. const asio::ip::tcp::resolver::results_type& endpoints)
  21. : io_context_(io_context),
  22. socket_(io_context)
  23. {
  24. do_connect(endpoints);
  25. }
  26. void write(const chat_message& msg)
  27. {
  28. asio::post(io_context_,
  29. [this, msg]()
  30. {
  31. bool write_in_progress = !write_msgs_.empty();
  32. write_msgs_.push_back(msg);
  33. if (!write_in_progress)
  34. {
  35. do_write();
  36. }
  37. });
  38. }
  39. void close()
  40. {
  41. asio::post(io_context_, [this]() { socket_.close(); });
  42. }
  43. private:
  44. void do_connect(const asio::ip::tcp::resolver::results_type& endpoints)
  45. {
  46. asio::async_connect(socket_, endpoints,
  47. [this](std::error_code ec, asio::ip::tcp::endpoint)
  48. {
  49. if (!ec)
  50. {
  51. do_read_header();
  52. }
  53. });
  54. }
  55. void do_read_header()
  56. {
  57. asio::async_read(socket_,
  58. asio::buffer(read_msg_.data(), chat_message::header_length),
  59. [this](std::error_code ec, std::size_t /*length*/)
  60. {
  61. if (!ec && read_msg_.decode_header())
  62. {
  63. do_read_body();
  64. }
  65. else
  66. {
  67. socket_.close();
  68. }
  69. });
  70. }
  71. void do_read_body()
  72. {
  73. asio::async_read(socket_,
  74. asio::buffer(read_msg_.body(), read_msg_.body_length()),
  75. [this](std::error_code ec, std::size_t /*length*/)
  76. {
  77. if (!ec)
  78. {
  79. do_read_header();
  80. }
  81. else
  82. {
  83. socket_.close();
  84. }
  85. });
  86. }
  87. void do_write()
  88. {
  89. asio::async_write(socket_,
  90. asio::buffer(write_msgs_.front().data(),
  91. write_msgs_.front().length()),
  92. [this](std::error_code ec, std::size_t /*length*/)
  93. {
  94. if (!ec)
  95. {
  96. write_msgs_.pop_front();
  97. if (!write_msgs_.empty())
  98. {
  99. do_write();
  100. }
  101. }
  102. else
  103. {
  104. socket_.close();
  105. }
  106. });
  107. }
  108. private:
  109. asio::io_context& io_context_;
  110. asio::ip::tcp::socket socket_;
  111. chat_message read_msg_;
  112. chat_message_queue write_msgs_;
  113. };
  114. #endif // CHAT_CLIENT_HPP