title: Chat server/client using ASIO, unable to find the client example code
body: <p>I'm about to use <a href="https://think-async.com/Asio/" rel="nofollow noreferrer">ASIO</a> for a chat server/client. When I downloaded ASIO, it had built-in examples for the different C++ versions. Since I will be using C++ 17/20, I decided to take that particular example.</p>
  <p>The problem is that it is missing the client example. Can I find their client example code somewhere for C++ 17/20? By C++ 17/20 I mean the client should use <em>coroutines</em>.</p>
  <p><a href="https://i.stack.imgur.com/9Bsxs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/9Bsxs.png" alt="enter image description here" /></a></p>
  <h3>chat_server.cpp</h3>
  <pre class="lang-cpp prettyprint-override"><code>//
  // chat_server.cpp
  // ~~~~~~~~~~~~~~~
  //
  // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  //
  // Distributed under the Boost Software License, Version 1.0. (See accompanying
  // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  //
  
  #include &lt;cstdlib&gt;
  #include &lt;deque&gt;
  #include &lt;iostream&gt;
  #include &lt;list&gt;
  #include &lt;memory&gt;
  #include &lt;set&gt;
  #include &lt;string&gt;
  #include &lt;utility&gt;
  #include &lt;asio/awaitable.hpp&gt;
  #include &lt;asio/detached.hpp&gt;
  #include &lt;asio/co_spawn.hpp&gt;
  #include &lt;asio/io_context.hpp&gt;
  #include &lt;asio/ip/tcp.hpp&gt;
  #include &lt;asio/read_until.hpp&gt;
  #include &lt;asio/redirect_error.hpp&gt;
  #include &lt;asio/signal_set.hpp&gt;
  #include &lt;asio/steady_timer.hpp&gt;
  #include &lt;asio/use_awaitable.hpp&gt;
  #include &lt;asio/write.hpp&gt;
  
  using asio::ip::tcp;
  using asio::awaitable;
  using asio::co_spawn;
  using asio::detached;
  using asio::redirect_error;
  using asio::use_awaitable;
  
  //----------------------------------------------------------------------
  
  class chat_participant
  {
  public:
    virtual ~chat_participant() {}
    virtual void deliver(const std::string&amp; msg) = 0;
  };
  
  typedef std::shared_ptr&lt;chat_participant&gt; chat_participant_ptr;
  
  //----------------------------------------------------------------------
  
  class chat_room
  {
  public:
    void join(chat_participant_ptr participant)
    {
      participants_.insert(participant);
      for (auto msg: recent_msgs_)
        participant-&gt;deliver(msg);
    }
  
    void leave(chat_participant_ptr participant)
    {
      participants_.erase(participant);
    }
  
    void deliver(const std::string&amp; msg)
    {
      recent_msgs_.push_back(msg);
      while (recent_msgs_.size() &gt; max_recent_msgs)
        recent_msgs_.pop_front();
  
      for (auto participant: participants_)
        participant-&gt;deliver(msg);
    }
  
  private:
    std::set&lt;chat_participant_ptr&gt; participants_;
    enum { max_recent_msgs = 100 };
    std::deque&lt;std::string&gt; recent_msgs_;
  };
  
  //----------------------------------------------------------------------
  
  class chat_session
    : public chat_participant,
      public std::enable_shared_from_this&lt;chat_session&gt;
  {
  public:
    chat_session(tcp::socket socket, chat_room&amp; room)
      : socket_(std::move(socket)),
        timer_(socket_.get_executor()),
        room_(room)
    {
      timer_.expires_at(std::chrono::steady_clock::time_point::max());
    }
  
    void start()
    {
      room_.join(shared_from_this());
  
      co_spawn(socket_.get_executor(),
          [self = shared_from_this()]{ return self-&gt;reader(); },
          detached);
  
      co_spawn(socket_.get_executor(),
          [self = shared_from_this()]{ return self-&gt;writer(); },
          detached);
    }
  
    void deliver(const std::string&amp; msg)
    {
      write_msgs_.push_back(msg);
      timer_.cancel_one();
    }
  
  private:
    awaitable&lt;void&gt; reader()
    {
      try
      {
        for (std::string read_msg;;)
        {
          std::size_t n = co_await asio::async_read_until(socket_,
              asio::dynamic_buffer(read_msg, 1024), &quot;\n&quot;, use_awaitable);
  
          room_.deliver(read_msg.substr(0, n));
          read_msg.erase(0, n);
        }
      }
      catch (std::exception&amp;)
      {
        stop();
      }
    }
  
    awaitable&lt;void&gt; writer()
    {
      try
      {
        while (socket_.is_open())
        {
          if (write_msgs_.empty())
          {
            asio::error_code ec;
            co_await timer_.async_wait(redirect_error(use_awaitable, ec));
          }
          else
          {
            co_await asio::async_write(socket_,
                asio::buffer(write_msgs_.front()), use_awaitable);
            write_msgs_.pop_front();
          }
        }
      }
      catch (std::exception&amp;)
      {
        stop();
      }
    }
  
    void stop()
    {
      room_.leave(shared_from_this());
      socket_.close();
      timer_.cancel();
    }
  
    tcp::socket socket_;
    asio::steady_timer timer_;
    chat_room&amp; room_;
    std::deque&lt;std::string&gt; write_msgs_;
  };
  
  //----------------------------------------------------------------------
  
  awaitable&lt;void&gt; listener(tcp::acceptor acceptor)
  {
    chat_room room;
  
    for (;;)
    {
      std::make_shared&lt;chat_session&gt;(
          co_await acceptor.async_accept(use_awaitable),
          room
        )-&gt;start();
    }
  }
  
  //----------------------------------------------------------------------
  
  int main(int argc, char* argv[])
  {
    try
    {
      if (argc &lt; 2)
      {
        std::cerr &lt;&lt; &quot;Usage: chat_server &lt;port&gt; [&lt;port&gt; ...]\n&quot;;
        return 1;
      }
  
      asio::io_context io_context(1);
  
      for (int i = 1; i &lt; argc; ++i)
      {
        unsigned short port = std::atoi(argv[i]);
        co_spawn(io_context,
            listener(tcp::acceptor(io_context, {tcp::v4(), port})),
            detached);
      }
  
      asio::signal_set signals(io_context, SIGINT, SIGTERM);
      signals.async_wait([&amp;](auto, auto){ io_context.stop(); });
  
      io_context.run();
    }
    catch (std::exception&amp; e)
    {
      std::cerr &lt;&lt; &quot;Exception: &quot; &lt;&lt; e.what() &lt;&lt; &quot;\n&quot;;
    }
  
    return 0;
  }
  </code></pre>
  <p><strong>Edit:</strong></p>
  <p>I tried to create a client myself, but I'm not able to write messages and everyone to be able to read them yet, basically what the C++ 11 example chat client code does.</p>
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;cstdlib&gt;
  #include &lt;deque&gt;
  #include &lt;iostream&gt;
  #include &lt;thread&gt;
  #include &lt;string&gt;
  
  #include &lt;asio.hpp&gt;
  
  using asio::ip::tcp;
  using asio::awaitable;
  using asio::co_spawn;
  using asio::detached;
  using asio::redirect_error;
  using asio::use_awaitable;
  
  std::deque&lt;std::string&gt; write_msgs_;
  
  void stop(tcp::socket&amp; socket)
  {
      socket.close();
  }
  
  awaitable&lt;void&gt; reader(tcp::socket&amp; socket)
  {
      try
      {
          for (std::string read_msg;;)
          {
              std::size_t n = co_await asio::async_read_until(socket, asio::dynamic_buffer(read_msg, 1024), &quot;\n&quot;, use_awaitable);
  
              //room_.deliver(read_msg.substr(0, n));
              read_msg.erase(0, n);
          }
      }
      catch (std::exception&amp;)
      {
          stop(socket);
      }
  }
  
  awaitable&lt;void&gt; writer(tcp::socket&amp; socket)
  {
      try
      {
          while (socket.is_open())
          {
              if (write_msgs_.empty())
              {
                  asio::error_code ec;
                  //co_await timer_.async_wait(redirect_error(use_awaitable, ec));
              }
              else
              {
                  co_await asio::async_write(socket, asio::buffer(write_msgs_.front()), use_awaitable);
                  write_msgs_.pop_front();
              }
          }
      }
      catch (std::exception&amp;)
      {
          stop(socket);
      }
  }
  
  awaitable&lt;void&gt; connect(tcp::socket socket, const tcp::endpoint&amp; endpoint)
  {
      std::error_code ec;
  
      co_await socket.async_connect(endpoint, redirect_error(use_awaitable, ec));
  
      co_spawn(socket.get_executor(), [&amp;] { return reader(socket); }, detached);
      co_spawn(socket.get_executor(), [&amp;] { return writer(socket); }, detached);
  
      if (!ec)
      {
          std::cout &lt;&lt; &quot;Connected to &quot; &lt;&lt; endpoint &lt;&lt; std::endl;
      }
  }
  
  int main()
  {
      try
      {
          asio::io_context io_context(1);
          tcp::endpoint endpoint(asio::ip::make_address(&quot;127.0.0.1&quot;), 666);
          tcp::socket socket(io_context);
  
          co_spawn(io_context, connect(std::move(socket), endpoint), detached);
  
          asio::signal_set signals(io_context, SIGINT, SIGTERM);
          signals.async_wait([&amp;](auto, auto) { io_context.stop(); });
          
          io_context.run();
      }
      catch (std::exception&amp; e)
      {
          std::cerr &lt;&lt; &quot;Exception: &quot; &lt;&lt; e.what() &lt;&lt; &quot;\n&quot;;
      }
  
      return 0;
  }
  
  </code></pre>