title: Boost::Asio : Why does async_write truncate the buffer when sending it through the given socket?
body: <p>I'm currently attempting to design a fairly simple <code>boost::asio</code> server. My first unit test is fairly simple: send a JSON request <code>{&quot;COMMAND&quot;: &quot;ADD_1&quot;, &quot;VALUE&quot; : 1}</code> and receive the following response:</p>
  <pre><code>{
      &quot;SUCCESS&quot; : true,
      &quot;VALUE&quot; : 2
  }
  </code></pre>
  <p>However, instead, the reply is truncated by one character after being <code>read</code> from the socket:</p>
  <pre><code>Reply is: {
      &quot;SUCCESS&quot; : true,
      &quot;VALUE&quot; : 2
  
  Process finished with exit code 0
  </code></pre>
  <p>The code to write to the socket is fairly simple, a member function of a class <code>RequestContext</code>:</p>
  <pre><code>    void RequestContext::DoWrite(std::size_t length)
      {
          JSONCPP_STRING parse_err;
          Json::Value json_req, json_resp;
          auto self(this-&gt;shared_from_this());
          std::string client_req_str(data_);
  
          if (reader_-&gt;parse(client_req_str.c_str(),
                             client_req_str.c_str() +
                             client_req_str.length(),
                             &amp;json_req, &amp;parse_err))
          {
              try {
                  // Get JSON response.
                  json_resp = ProcessRequest(json_req);
                  json_resp[&quot;SUCCESS&quot;] = true;
              } catch (const std::exception &amp;ex) {
                  // If json parsing failed.
                  json_resp[&quot;SUCCESS&quot;] = false;
                  json_resp[&quot;ERRORS&quot;] = std::string(ex.what());
              }
          } else {
              // If json parsing failed.
              json_resp[&quot;SUCCESS&quot;] = false;
              json_resp[&quot;ERRORS&quot;] = std::string(parse_err);
          }
  
          std::string resp = Json::writeString(writer_, json_resp);
  
          boost::asio::async_write(socket_,
                                   boost::asio::buffer(&amp;resp[0], resp.size()),
                                   [this, self]
                                   (boost::system::error_code ec,
                                    std::size_t bytes_xfered) {
                                      if (!ec)     DoRead();
                                   });
      }
  </code></pre>
  <p>I have verified that <code>ProcessRequest</code> returns the correct value, so the issue is evidently with <code>async_write</code>. I have tried increasing the value of the second argument to <code>async_write</code>, but it seems to have no effect. What am I doing wrong?</p>
  <p>A minimum reproducible example can be found below:</p>
  <pre><code>#include &lt;cstdlib&gt;
  #include &lt;iostream&gt;
  #include &lt;memory&gt;
  #include &lt;utility&gt;
  #include &lt;boost/asio.hpp&gt;
  #include &lt;boost/system/error_code.hpp&gt;
  #include &lt;json/json.h&gt;
  
  using boost::asio::ip::tcp;
  using boost::system::error_code;
  /// NOTE: This class exists exclusively for unit testing.
  class RequestClass {
  public:
      /**
       * Initialize class with value n to add sub from input values.
       *
       * @param n Value to add/sub from input values.
       */
      explicit RequestClass(int n) : n_(n) {}
  
      /// Value to add/sub from
      int n_;
  
      /**
       * Add n to value in JSON request.
       *
       * @param request JSON request with field &quot;value&quot;.
       * @return JSON response containing modified field &quot;value&quot; = [original_value] + n.
       */
      [[nodiscard]] Json::Value add_n(const Json::Value &amp;request) const
      {
          Json::Value resp;
          resp[&quot;SUCCESS&quot;] = true;
  
          // If value is present in request, return value + 1, else return error.
          if (request.get(&quot;VALUE&quot;, NULL) != NULL) {
              resp[&quot;VALUE&quot;] = request[&quot;VALUE&quot;].asInt() + this-&gt;n_;
          } else {
              resp[&quot;SUCCESS&quot;] = false;
              resp[&quot;ERRORS&quot;] = &quot;Invalid value.&quot;;
          }
          return resp;
      }
  
      /**
       * Sun n from value in JSON request.
       *
       * @param request JSON request with field &quot;value&quot;.
       * @return JSON response containing modified field &quot;value&quot; = [original_value] - n.
       */
      [[nodiscard]] Json::Value sub_n(const Json::Value &amp;request) const
      {
          Json::Value resp, value;
          resp[&quot;SUCCESS&quot;] = true;
  
          // If value is present in request, return value + 1, else return error.
          if (request.get(&quot;VALUE&quot;, NULL) != NULL) {
              resp[&quot;VALUE&quot;] = request[&quot;VALUE&quot;].asInt() - this-&gt;n_;
          } else {
              resp[&quot;SUCCESS&quot;] = false;
              resp[&quot;ERRORS&quot;] = &quot;Invalid value.&quot;;
          }
          return resp;
      }
  };
  
  typedef std::function&lt;Json::Value(RequestClass, const Json::Value &amp;)&gt; RequestClassMethod;
  
  template&lt;class RequestHandler, class RequestClass&gt;
  class RequestContext :
      public std::enable_shared_from_this&lt;RequestContext&lt;RequestHandler,
                                                         RequestClass&gt;&gt;
  {
  public:
      typedef std::map&lt;std::string, RequestHandler&gt; CommandMap;
  
      RequestContext(tcp::socket socket, CommandMap commands,
                     RequestClass *request_class_inst)
          : socket_(std::move(socket))
          , commands_(std::move(commands))
          , request_class_inst_(request_class_inst)
          , reader_((new Json::CharReaderBuilder)-&gt;newCharReader())
      {}
  
      void Run()
      {
          DoRead();
      }
  
      void Kill()
      {
          continue_ = false;
      }
  
  private:
      tcp::socket socket_;
      RequestClass *request_class_inst_;
      CommandMap commands_;
      /// Reads JSON.
      const std::unique_ptr&lt;Json::CharReader&gt; reader_;
      /// Writes JSON.
      Json::StreamWriterBuilder writer_;
      bool continue_ = true;
      char data_[2048];
  
      void DoRead()
      {
          auto self(this-&gt;shared_from_this());
          socket_.async_read_some(boost::asio::buffer(data_, 2048),
                                  [this, self](error_code ec, std::size_t length)
                                  {
                                    if (!ec)
                                    {
                                        DoWrite(length);
                                    }
                                  });
      }
  
      void DoWrite(std::size_t length)
      {
          JSONCPP_STRING parse_err;
          Json::Value json_req, json_resp;
          auto self(this-&gt;shared_from_this());
          std::string client_req_str(data_);
  
          if (reader_-&gt;parse(client_req_str.c_str(),
                             client_req_str.c_str() +
                             client_req_str.length(),
                             &amp;json_req, &amp;parse_err))
          {
              try {
                  // Get JSON response.
                  json_resp = ProcessRequest(json_req);
                  json_resp[&quot;SUCCESS&quot;] = true;
              } catch (const std::exception &amp;ex) {
                  // If json parsing failed.
                  json_resp[&quot;SUCCESS&quot;] = false;
                  json_resp[&quot;ERRORS&quot;] = std::string(ex.what());
              }
          } else {
              // If json parsing failed.
              json_resp[&quot;SUCCESS&quot;] = false;
              json_resp[&quot;ERRORS&quot;] = std::string(parse_err);
          }
  
          std::string resp = Json::writeString(writer_, json_resp);
  
          boost::asio::async_write(socket_,
                                   boost::asio::buffer(&amp;resp[0], resp.size()),
                                   [this, self]
                                   (boost::system::error_code ec,
                                    std::size_t bytes_xfered) {
                                      if (!ec)     DoRead();
                                   });
      }
  
      Json::Value ProcessRequest(Json::Value request)
      {
          Json::Value response;
          std::string command = request[&quot;COMMAND&quot;].asString();
  
          // If command is not valid, give a response with an error.
          if(commands_.find(command) == commands_.end()) {
              response[&quot;SUCCESS&quot;] = false;
              response[&quot;ERRORS&quot;] = &quot;Invalid command.&quot;;
          }
              // Otherwise, run the relevant handler.
          else {
              RequestHandler handler = commands_.at(command);
              response = handler(*request_class_inst_, request);
          }
  
          return response;
      }
  
  };
  
  template&lt;class RequestHandler, class RequestClass&gt;
  class Server {
  public:
      typedef std::map&lt;std::string, RequestHandler&gt; CommandMap;
  
      Server(boost::asio::io_context &amp;io_context, short port,
             const CommandMap &amp;commands,
             RequestClass *request_class_inst)
          : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
          , commands_(commands)
          , request_class_inst_(request_class_inst)
      {
          DoAccept();
      }
  
      ~Server()
      {
          Kill();
      }
  
      void Kill()
      {
          continue_ = false;
      }
  
  private:
      tcp::acceptor acceptor_;
      bool continue_ = true;
      CommandMap commands_;
      RequestClass *request_class_inst_;
  
      void DoAccept()
      {
          acceptor_.async_accept(
              [this](boost::system::error_code ec, tcp::socket socket) {
                  if (!ec)
                      std::make_shared&lt;RequestContext&lt;RequestHandler, RequestClass&gt;&gt;
                          (std::move(socket), commands_, request_class_inst_)-&gt;Run();
                  DoAccept();
              });
      }
  };
  
  void RunServer(short port)
  {
      boost::asio::io_context io_context;
      auto *request_inst = new RequestClass(1);
      std::map&lt;std::string, RequestClassMethod&gt; commands {
          {&quot;ADD_1&quot;, std::mem_fn(&amp;RequestClass::add_n)},
          {&quot;SUB_1&quot;, std::mem_fn(&amp;RequestClass::sub_n)}
      };
      Server&lt;RequestClassMethod, RequestClass&gt; s(io_context, port, commands,
                                                 request_inst);
  
      io_context.run();
  }
  
  void RunServerInBackground(short port)
  {
      std::thread t([port] { RunServer(port); });
      t.detach();
  }
  
  
  
  int main()
  {
      try
      {
          RunServerInBackground(5000);
          boost::asio::io_context io_context;
          tcp::socket s(io_context);
          tcp::resolver resolver(io_context);
  
          boost::asio::connect(s, resolver.resolve(&quot;127.0.0.1&quot;, &quot;5000&quot;));
          char request[2048] = R&quot;({&quot;COMMAND&quot;: &quot;ADD_1&quot;, &quot;VALUE&quot; : 1})&quot;;
          size_t request_length = std::strlen(request);
          boost::asio::write(s, boost::asio::buffer(request, request_length));
          char reply[2048];
          size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
          std::cout &lt;&lt; &quot;Reply is: &quot;;
          std::cout &lt;&lt; reply &lt;&lt; std::endl;
      }
      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>