2016-11-27 5 views
2

Die erklären folgende ist ein Beispiel, das ich von einem trivialen TCP-Server geschrieben und dazu passenden Client Praktizieren boost die Asio Bibliothek zu starten, Example TCP Client/Server.kann nicht schlechte Bandbreite Leistung mit boost Asio TCP-Sockets

  • Der Client verbindet und sendet Daten einfach so schnell wie möglich aus einem Speicherpuffer.
  • Der Server lauscht nur für Nachrichten und druckt, wie viele Bytes es von einer kompletten Nachricht bekam.
  • Das ist es - nichts mehr. Booth-Beispiele laufen auf ein paar Threads, meistens werden Standardeinstellungen verwendet, es gibt keine willkürlich platzierten Betten, die Dinge wegwerfen könnten ... Sie sind wirklich ziemlich einfach zu folgen, es gibt praktisch nichts anderes als einen direkten Aufruf, um mit dem Ziel zu boosten das Problem zu isolieren.

    Die Sache ist, dass die Ausgabe des Client ist folgende:

    Mbyte/s: 51,648908, Gbyte/s: 0,051649, Mbits/sec: 413,191267, Gbits/sec: 0,413191

    Hinweise :

    • Ich bin gerade mit meinem Laptop aus Batterieleistung ausgeführt. Wenn ich es an eine Stromversorgungsbuchse anschließe, springt es auf ~ 0,7 Gbit/s.
    • Ich habe versucht, kleine 2048 Byte Nachrichten an die aktuellen 8 Mbyte Nachrichten zu senden.
    • Ich habe versucht mit dem Nagle-Algorithmus aktiviert und deaktiviert.
    • Ich habe versucht, Größenänderung senden und OS-Puffer zu empfangen.
    • All dies wird über Loopback ausgeführt wird, 127.0.0.1.
    • Überwachung Loopback über Wireshark zeigt die gleiche geringe Bandbreite Nutzung.
    • Der eigentliche Punkt, der mich dazu veranlasste, die Frage zu schreiben, ist diese. Die iperf tool ist in der Lage, 33,0 Gbit/s mit TCP über localhost zu erreichen.

      $ iperf --client 127.0.0.1 
      ------------------------------------------------------------ 
      Client connecting to 127.0.0.1, TCP port 5001 
      TCP window size: 2.50 MByte (default) 
      ------------------------------------------------------------ 
      [ 3] local 127.0.0.1 port 41952 connected with 127.0.0.1 port 5001 
      [ ID] Interval  Transfer  Bandwidth 
      [ 3] 0.0-10.0 sec 38.4 GBytes 33.0 Gbits/sec 
      

      Alle sucht nach etwas entlang der Linien von „TCP-Boost Asio Performance“ sind in der Regel mit Vorschlägen aufzuwickeln nagle oder Einstellung OS Buchse Puffer zu deaktivieren.

      Wenn jemand mich in der richtigen Richtung zeigen könnte, zu verstehen, warum ich so niedrige Bandbreite Leistung mit boost zu erhalten bin Asio würde ich es sehr zu schätzen!

    +0

    Ich habe es bis zu 3GBps bekommen, indem ich einfach alle Socket-Empfangs- und Sendepuffergrößen-Optionen auskommentiert und die erforderliche Größenanpassung auf TCP-Auto-Tuning verschoben habe. Außerdem habe ich den Server-Empfangscode geändert, um keine Iteration über den Puffer durchzuführen, das ist eine Verschwendung. Mein geänderter Code unter http://melpon.org/wandbox/permlink/UUlmqwH5tlD4Ah4f – Arunmu

    +0

    Es wäre besser zu sehen, was iperf macht. Kann es sein, dass es einen Kopiermechanismus verwendet, um einfach zu senden? – Arunmu

    +0

    Oh ... Ich habe nicht gesehen, es war 33G'bits pro Sekunde in iperf. Dann mit meinen Änderungen ist es 24Gbits pro Sekunde :). Nah genug, aber ich bin sicher, dass viel getan werden kann. Erneutes Ausführen zeigte diesmal etwas um 30 Gbps. – Arunmu

    Antwort

    3

    Zunächst lassen Sie mich die Dinge, weisen Sie für diese Art von Test falsch machen.

    1. Manuelle Einstellung der TCP-Puffergröße

    Das ist besser links für den TCP-Algorithmus, um herauszufinden, was die beste Größe ist. Dies wird üblicherweise während der Phase von TCP slow-start bestimmt, wo der TCP-Algorithmus schließlich auf der Grundlage der Überlastung auf eine bestmögliche window-size entscheidet. Da wir einen lokalen Host verwenden und auch eine Punkt-zu-Punkt-Verbindung ohne irgendwelche zwischen den Netzwerkkomponenten, wäre die Überlastung nahe Null.

    1. Aktivieren Nagles Algorithmus

    Dies benötigt nicht wirklich, da Sie nicht eingerahmt Pakete mit kurzer Länge zu senden. Es ist normalerweise dann, wenn das Einschalten von Nagles Ihnen einen Vorteil auf latency geben würde (für den Durchsatz bin ich nicht so sicher, ob es irgendeine Verbesserung geben würde).

    1. Unerwünschte Verarbeitung auf Serverseite

    Ich sehe, dass Sie über den Empfangspuffer iterieren und eine Art von sinnlos Scheck zu tun. iperf macht das sicher nicht. Ich habe diesen Codeabschnitt auskommentiert.

    1. Empfangen von Anwendungspuffergröße

    Ich weiß nicht, aber aus irgendeinem Grund haben Sie sich entschieden nur 2048 Bytes pro empfangen zu lesen. Ein besonderer Grund dafür? Ich habe es wieder auf die tatsächliche Größe geändert, die vom Client geschrieben wurde. Sie haben wahrscheinlich nur mehr Daten in den Server-Empfangsbereich eingereiht.

    Neuer Code Server:

    #include <thread> 
    #include <chrono> 
    #include <vector> 
    #include <signal.h> 
    #include <asio.hpp> 
    #include <system_error> 
    
    namespace 
    { 
    bool keepGoing = true; 
    void shutdown(int) 
    { 
         keepGoing = false; 
    } 
    
    std::size_t bytesAccum = 0; 
    void justReceive(std::error_code ec, std::size_t bytesReceived, 
        asio::ip::tcp::socket &socket, std::vector<unsigned char> &buffer) 
    { 
         bytesAccum += bytesReceived; 
    /* 
         auto end = buffer.begin() + bytesReceived; 
         for (auto it = buffer.begin(); it != end; ++it) 
         { 
           if (*it == 'e') 
           { 
             std::printf("server got: %lu\n", bytesAccum); 
             bytesAccum = 0; 
           } 
         } 
    */ 
         socket.async_receive(
          asio::buffer(buffer), 
          0, 
          [&] (auto ec, auto bytes) { 
           justReceive(ec, bytes, socket, buffer); 
          }); 
    } 
    } 
    
    int main(int, char **) 
    { 
         signal(SIGINT, shutdown); 
    
         asio::io_service io; 
         asio::io_service::work work(io); 
    
         std::thread t1([&]() { io.run(); }); 
         std::thread t2([&]() { io.run(); }); 
         std::thread t3([&]() { io.run(); }); 
         std::thread t4([&]() { io.run(); }); 
    
         asio::ip::tcp::acceptor acceptor(io, 
          asio::ip::tcp::endpoint(
           asio::ip::address::from_string("127.0.0.1"), 1234)); 
         asio::ip::tcp::socket socket(io); 
    
         // accept 1 client 
         std::vector<unsigned char> buffer(131072, 0); 
         acceptor.async_accept(socket, [&socket, &buffer](std::error_code ec) 
         { 
          // options 
          //socket.set_option(asio::ip::tcp::no_delay(true)); 
          //socket.set_option(asio::socket_base::receive_buffer_size(8192 * 2)); 
          //socket.set_option(asio::socket_base::send_buffer_size(8192)); 
    
          socket.async_receive(
           asio::buffer(buffer), 
           0, 
           [&](auto ec, auto bytes) { 
            justReceive(ec, bytes, socket, buffer); 
           }); 
         }); 
    
         while (keepGoing) 
         { 
           std::this_thread::sleep_for(std::chrono::seconds(1)); 
         } 
    
         io.stop(); 
    
         t1.join(); 
         t2.join(); 
         t3.join(); 
         t4.join(); 
    
         std::printf("server: goodbye\n"); 
    } 
    

    Neue Client-Code:

    #include <thread> 
    #include <chrono> 
    #include <vector> 
    #include <signal.h> 
    #include <asio.hpp> 
    #include <system_error> 
    
    namespace 
    { 
    bool keepGoing = true; 
    void shutdown(int) { keepGoing = false; } 
    } 
    
    int main(int, char **) 
    { 
         signal(SIGINT, shutdown); 
    
         asio::io_service io; 
         asio::io_service::work work(io); 
    
         std::thread t1([&]() { io.run(); }); 
         std::thread t2([&]() { io.run(); }); 
         std::thread t3([&]() { io.run(); }); 
         std::thread t4([&]() { io.run(); }); 
    
         asio::ip::tcp::socket socket(io); 
         auto endpoint = asio::ip::tcp::resolver(io).resolve({ 
          "127.0.0.1", "1234" }); 
         asio::connect(socket, endpoint); 
    
         // options to test 
         //socket.set_option(asio::ip::tcp::no_delay(true)); 
         //socket.set_option(asio::socket_base::receive_buffer_size(8192)); 
         //socket.set_option(asio::socket_base::send_buffer_size(8192 * 2)); 
    
         std::vector<unsigned char> buffer(131072, 0); 
         buffer.back() = 'e'; 
    
         std::chrono::time_point<std::chrono::system_clock> last = 
          std::chrono::system_clock::now(); 
    
         std::chrono::duration<double> delta = std::chrono::seconds(0); 
    
         std::size_t bytesSent = 0; 
    
         while (keepGoing) 
         { 
           // blocks during send 
           asio::write(socket, asio::buffer(buffer)); 
           //socket.send(asio::buffer(buffer)); 
    
           // accumulate bytes sent 
           bytesSent += buffer.size(); 
    
           // accumulate time spent sending 
           delta += std::chrono::system_clock::now() - last; 
           last = std::chrono::system_clock::now(); 
    
           // print information periodically 
           if (delta.count() >= 5.0) 
           { 
             std::printf("Mbytes/sec: %f, Gbytes/sec: %f, Mbits/sec: %f, Gbits/sec: %f\n", 
                bytesSent/1.0e6/delta.count(), 
                bytesSent/1.0e9/delta.count(), 
                8 * bytesSent/1.0e6/delta.count(), 
                8 * bytesSent/1.0e9/delta.count()); 
    
             // reset accumulators 
             bytesSent = 0; 
             delta = std::chrono::seconds(0); 
           } 
         } 
    
         io.stop(); 
    
         t1.join(); 
         t2.join(); 
         t3.join(); 
         t4.join(); 
    
         std::printf("client: goodbyte\n"); 
    } 
    

    HINWEIS: Ich benutzte Standalone-Version von asio, aber die Ergebnisse, wie durch die OP berichtet wurden, waren auf meinem Rechner reproduzierbar, das ist :

    MacBook Pro Yosemite - 2,6 GHz Intel Core i5 Prozessor - 8 GB DDR3 RAM .

    +1

    Vielen Dank für Ihre Beobachtungen! Ich habe meine Dateien beim Hochladen meiner Beispiele durcheinander gebracht, aber ich habe auch die standardmäßigen Boost :: Asio-Einstellungen ausprobiert (ohne mit Nagle- oder OS-Socket-Puffergrößen zu kämpfen). Was ich nicht ausprobiert hatte, war dein ** 4. Punkt **. Dies war konkret der Flaschenhals in meinem Beispiel! Boost hat einfach zu viel Arbeit mit einem so kleinen Inbound-Puffer auf der Server-Seite gemacht. Wenn ich es erweitere, bekomme ich auf meinem i5 8Gb RAM Linux System bis zu 40 Gbits/sec. Danke nochmal für die Hilfe! – JDR