title: Performance of Boost UDP Sockets - Low throughput?
body: <p>I am having some trouble with the performance of Boost ASIO UDP - or atleast - I think so.</p>
  
  <p>I have put together a simple client/server application to illustrate:</p>
  
  <ol>
  <li>The Client starts to send large (65K) UDP packages to the server - slowly</li>
  <li>The server immediately sends back an ACK package when a package is received</li>
  <li>The Client keeps an eye on the rate these ACK packages are coming in - and sends outgoing packages a little faster - in order to have the speed pick up.</li>
  </ol>
  
  <p>(Package loss/resending etc. is not a concern in the sample code.)</p>
  
  <p>When originally writing this in C# the Client quickly reached the limit of the NIC - about 125 megabyte/sec. When rewriting the same code in C++ with Boost - speeds stop at under 2 megabyte/sec. </p>
  
  <p><a href="https://i.stack.imgur.com/HLYOE.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/HLYOE.png" alt="enter image description here"></a></p>
  
  <p>CPU for both client and server are 1-2%. No memory issues. Running both server and client on localhost. Running Windows 10, VS 2013, Boost 1.60.</p>
  
  <p>I have tried using async send/receive methods of Boost but that did not seem to help. <a href="https://stackoverflow.com/questions/31128014/how-to-increase-throughput-of-boost-asio-udp-client-application">How to increase throughput of Boost ASIO, UDP client application</a></p>
  
  <p>Is there a problem related to two threads sending/receiving from the same boost socket? <a href="https://stackoverflow.com/questions/1234750/c-socket-server-unable-to-saturate-cpu/1238315#1238315">C++ Socket Server - Unable to saturate CPU</a></p>
  
  <p>PS - I started programming C++ 2 months ago - so there <em>might</em> be a really stupid mistake here somewhere.. but I am unable to see where exactly. Any help/thoughts would be greatly appriciated.</p>
  
  <p><strong>CLIENT:</strong></p>
  
  <pre class="lang-cpp prettyprint-override"><code>#pragma once
  #include &lt;boost/smart_ptr/shared_ptr.hpp&gt;
  #include &lt;boost/asio.hpp&gt;
  #include &lt;boost/thread/v2/thread.hpp&gt;
  #include &lt;boost/thread/detail/thread.hpp&gt;
  #include &lt;chrono&gt;
  #include &lt;boost/lexical_cast.hpp&gt;
  
  #define EXPOSE_IN_DLL __declspec(dllexport)
  
  namespace dummy{
  
      EXPOSE_IN_DLL class DummyClient
      {
          public:
  
              // How fast the client is receiving acks - e.g. every 200 ms.
              double MillisecondsPerAck = 200; 
  
              //How fast the client should be sending packages (meaning - how long it should sleep between packages)
              long long MinimumOfMillisecondsToUsePerSentPackage = 200; 
  
              //How often the code should throttle (calculate new value for 'MinimumOfMillisecondsToUsePerSentPackage')
              int intervalMilliseconds = 500;
  
              //How much faster we should send than receive (how fast we should increase the speed)
              const double ThrottleAgressiveness = 0.7;
  
              //Counters
              int AcksSinceLastTime = 0;
              int AcksLastTime = 0;
              int PackagesSent = 0;
              int AcksReceived = 0;
              long long BytesSentAndAcked = 0;
  
              //Size of UDP Package to send. IP Layer (NIC) will break larger packages into smaller ones (MTU).
              static const int PacketSize = 65000; 
  
              std::shared_ptr&lt;boost::asio::io_service&gt; io_service;
              std::shared_ptr&lt;boost::asio::ip::udp::socket&gt; socket;
              std::shared_ptr&lt;boost::asio::ip::udp::endpoint&gt; udpEndPoint;
  
              EXPOSE_IN_DLL DummyClient()
              {
                  boost::thread receiverThread(&amp;DummyClient::SendPackages, this);
                  receiverThread.detach();
  
                  using namespace std::chrono;
                  auto started = duration_cast&lt;milliseconds&gt;(system_clock::now().time_since_epoch()).count();
  
                  while (true){
  
                      boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
  
                      auto elapsedMilliseconds = duration_cast&lt;milliseconds&gt;(system_clock::now().time_since_epoch()).count() - started;
  
                      system("cls");
                      std::cout &lt;&lt; "                  ############  UDP  CLIENT  ############   \n\n";
                      std::cout &lt;&lt; "                             Packages sent: " &lt;&lt; PackagesSent &lt;&lt; "\n";
                      std::cout &lt;&lt; "                             Acks received: " &lt;&lt; AcksReceived &lt;&lt; "\n";
                      std::cout &lt;&lt; "                           Bytes delivered: " &lt;&lt; BytesToSize(BytesSentAndAcked) &lt;&lt; "\n";
                      std::cout &lt;&lt; "---------------------------------------------------------------------------\n";
  
                      if (AcksReceived &gt; 0 &amp;&amp; PackagesSent &gt; 0)
                          std::cout &lt;&lt; "                          Acked percentage: " &lt;&lt; 100.0 * AcksReceived / PackagesSent &lt;&lt; "\n";
  
                      std::cout &lt;&lt; "---------------------------------------------------------------------------\n";
                      std::cout &lt;&lt; "                                 Bandwidth: " &lt;&lt; BytesToSize(1000 * BytesSentAndAcked / elapsedMilliseconds) &lt;&lt; "/sec\n";
                      std::cout &lt;&lt; "---------------------------------------------------------------------------\n";
                      std::cout &lt;&lt; "                        MilliSecondsPerAck: " &lt;&lt; MillisecondsPerAck &lt;&lt; "\n";
                      std::cout &lt;&lt; "                     ThrottleAgressiveness: " &lt;&lt; ThrottleAgressiveness &lt;&lt; "\n";
                      std::cout &lt;&lt; "  MinimumOfMillisecondsToUsePerSentPackage: " &lt;&lt; MinimumOfMillisecondsToUsePerSentPackage &lt;&lt; "\n";
                      std::cout &lt;&lt; "---------------------------------------------------------------------------\n";
                  }
              }
  
              EXPOSE_IN_DLL ~DummyClient(){
  
              };
  
      private:
  
          void SendPackages(){
              io_service = std::make_shared&lt;boost::asio::io_service&gt;();
              socket = std::make_shared&lt;boost::asio::ip::udp::socket&gt;(*io_service);
              udpEndPoint = std::make_shared&lt;boost::asio::ip::udp::endpoint&gt;(boost::asio::ip::address_v4::from_string("127.0.0.1"), 56000);
              socket-&gt;open(boost::asio::ip::udp::v4());
  
              //Start throtteling thread
              boost::thread throttleThread(&amp;DummyClient::ThrottleThread, this);
  
              //Start Receiver thread - that listens for ACK packages from the Dummy server
              boost::thread receiverThread(&amp;DummyClient::ReceiverThread, this);
  
              //Start sending packages - slowly 
              unsigned char dummyData[PacketSize];
              auto bufferToSend = boost::asio::buffer(dummyData, PacketSize);
              for (int i = 0; i &lt; 100000; i++)
              {
                  //Send
                  socket-&gt;send_to(bufferToSend, *udpEndPoint, boost::asio::socket_base::message_do_not_route);
  
                  PackagesSent++;
  
                  //Check if we need to sleep a little (throtteling) before sending next package
                  if (MinimumOfMillisecondsToUsePerSentPackage &gt; 0)
                      boost::this_thread::sleep_for(boost::chrono::milliseconds(MinimumOfMillisecondsToUsePerSentPackage));
              }
          }
  
          //"Acks" are received here - we are just counting them to get the rate they're coming in at.
          void ReceiverThread(){
  
              //Need to wait until first package is sent - so that the local andpoint is bound
              while (PackagesSent == 0){
                  boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
              }
  
              //Set up receiving buffer
              unsigned char receiveBuffer[100];
              auto bufferToReceiveInto = boost::asio::buffer(receiveBuffer, 100);
              boost::asio::ip::udp::endpoint senderEndPoint;
  
              //Start Receiving!
              while (true){
                  socket-&gt;receive_from(bufferToReceiveInto, senderEndPoint);
                  AcksReceived++;
                  BytesSentAndAcked += PacketSize;
              }
          }
  
  
          //Counts acks per interval - and adjusts outgoing speed accordingly.
          void ThrottleThread()
          {
              while (true)
              {
                  boost::this_thread::sleep_for(boost::chrono::milliseconds(intervalMilliseconds));
  
                  //Find out how many packages we got since last time - and send a little bit faster than this number.
                  if (PackagesSent &gt; 0)
                  {
                      AcksSinceLastTime = AcksReceived - AcksLastTime;
                      AcksLastTime = AcksReceived;
  
                      if (AcksSinceLastTime == 0)
                      {
                          //No new packages got acked - slow the down!
                          MinimumOfMillisecondsToUsePerSentPackage = 200;
                          continue;
                      }
  
                      //Increase sending speed to a little bit faster than we're receiving packages
                      MillisecondsPerAck = 1.0 * intervalMilliseconds / AcksSinceLastTime;
                      MinimumOfMillisecondsToUsePerSentPackage = MillisecondsPerAck * ThrottleAgressiveness;
                  }
              }
          }
  
  
          //Util method
          std::string BytesToSize(long long Bytes){
              float tb = 1099511627776;
              float gb = 1073741824;
              float mb = 1048576;
              float kb = 1024;
  
              std::string returnSize = "";
  
              if (Bytes &gt;= tb){
                  returnSize += boost::lexical_cast&lt;std::string&gt;((float)Bytes / tb);
                  returnSize += " TB";
              }
              else if (Bytes &gt;= gb &amp;&amp; Bytes &lt; tb)
              {
                  returnSize += boost::lexical_cast&lt;std::string&gt;((float)Bytes / gb);
                  returnSize += " GB";
              }
              else if (Bytes &gt;= mb &amp;&amp; Bytes &lt; gb){
                  returnSize += boost::lexical_cast&lt;std::string&gt;((float)Bytes / mb);
                  returnSize += " MB";
              }
              else if (Bytes &gt;= kb &amp;&amp; Bytes &lt; mb){
                  returnSize += boost::lexical_cast&lt;std::string&gt;((float)Bytes / kb);
                  returnSize += " KB";
              }
              else{
                  returnSize += boost::lexical_cast&lt;std::string&gt;(Bytes);
                  returnSize += " Bytes";
              }
              return returnSize;
          }
      };
  }
  </code></pre>
  
  <p><strong>SERVER:</strong></p>
  
  <pre class="lang-cpp prettyprint-override"><code>#pragma once
  
  #include &lt;boost/asio.hpp&gt;
  #include &lt;boost/smart_ptr/shared_ptr.hpp&gt;
  #include &lt;boost/thread/v2/thread.hpp&gt;
  #include &lt;boost/thread/detail/thread.hpp&gt;
  
  #define EXPOSE_IN_DLL __declspec(dllexport)
  
  using namespace boost::asio;
  
  namespace dummy{
  class DummyServer
  {
      public:
  
          std::shared_ptr&lt;ip::udp::socket&gt; listenSocket;
          std::shared_ptr&lt;io_service&gt; listenIoService;
  
          int PackagesReceived = 0;
  
          EXPOSE_IN_DLL DummyServer()
          {
              boost::thread receiverThread(&amp;DummyServer::ReceivePackages, this);
              receiverThread.detach();
  
              //Print status
              while (true){
                  boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
                  system("cls");
                  std::cout &lt;&lt; "      ############  UDP  SERVER  ############   \n\n";
                  std::cout &lt;&lt; "       Packages received: " &lt;&lt; PackagesReceived &lt;&lt; "\n";
              }
          }
  
          EXPOSE_IN_DLL ~DummyServer(){}
  
  
          void ReceivePackages(){
              //Start Receiver thread
              listenIoService = std::make_shared&lt;io_service&gt;();
              listenSocket = std::make_shared&lt;ip::udp::socket&gt;(*listenIoService, ip::udp::endpoint(ip::udp::v4(), 56000));
  
              //Set up receiving buffer
              auto bytesReceived = 0;
              unsigned char receiveBuffer[1024 * 70];
              auto bufferToReceiveInto = boost::asio::buffer(receiveBuffer, 1024 * 70);
  
              unsigned char returnBufferBuffer[10];
              auto bufferToSendBackToClient = boost::asio::buffer(returnBufferBuffer, 10);
  
              ip::udp::endpoint senderEndPoint;
              //Receive packages
              while (true){
                  listenSocket-&gt;receive_from(bufferToReceiveInto, senderEndPoint);
                  PackagesReceived++;
  
                  //Send an "Ack" package back to client - letting him know that a package successfully made it.
                  //Doesn't matter what the package contains - since client is just counting.
                  listenSocket-&gt;send_to(bufferToSendBackToClient, senderEndPoint);
              }
      }
  };
  </code></pre>
  
  <p>}</p>