Zunächst lassen Sie mich die Dinge, weisen Sie für diese Art von Test falsch machen.
- 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.
- 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).
- 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.
- 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 .
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
Es wäre besser zu sehen, was iperf macht. Kann es sein, dass es einen Kopiermechanismus verwendet, um einfach zu senden? – Arunmu
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