Программирование сокетов C ++: максимизировать пропускную способность / пропускную способность на локальном хосте (я получаю только 3 Гбит / с вместо 23 Гбит / с) - PullRequest
4 голосов
/ 31 июля 2011

Я хочу создать сервер / клиент C ++, который максимизирует пропускную способность по сравнению с TCP-сокетом на моем локальном хосте.В качестве подготовки я использовал iperf , чтобы узнать максимальную пропускную способность моего i7 MacBookPro.

------------------------------------------------------------
Server listening on TCP port 5001
TCP window size:  256 KByte (default)
------------------------------------------------------------
[  4] local 127.0.0.1 port 5001 connected with 127.0.0.1 port 51583
[  4]  0.0-120.0 sec   329 GBytes  23.6 Gbits/sec

Без каких-либо настроек ipref показал мне, что я могу достичь по крайней мере 23,2 Гбит/ с.Затем я сделал свою собственную реализацию C ++ сервера / клиента, вы можете найти полный код здесь: https://gist.github.com/1116635

В этом коде я в основном передаю массив размером 1024 байта с каждой операцией чтения / записи.Так что мой цикл отправки на сервере выглядит следующим образом:

   int n;

   int x[256];

   //fill int array
   for (int i=0;i<256;i++)
   {
       x[i]=i;
   }

   for (int i=0;i<(4*1024*1024);i++)
   {
       n = write(sock,x,sizeof(x));
       if (n < 0) error("ERROR writing to socket");
   }

Мой цикл приема на клиенте выглядит следующим образом:

int x[256]; 

for (int i=0;i<(4*1024*1024);i++)
{
    n = read(sockfd,x,((sizeof(int)*256)));
    if (n < 0) error("ERROR reading from socket");
}

Как указано в заголовке, выполняется это (скомпилировано с-O3) приводит к следующему времени выполнения, которое составляет около 3 Гбит / с:

./client 127.0.0.1 1234
Elapsed time for Reading 4GigaBytes of data over socket on localhost: 9578ms

Где я теряю пропускную способность, что я делаю неправильно?Опять же, полный код можно увидеть здесь: https://gist.github.com/1116635

Любая помощь приветствуется!

Ответы [ 4 ]

5 голосов
/ 31 июля 2011
  • Использовать большие буферы (т.е. делать меньше библиотечных / системных вызовов)
  • Использовать асинхронные API
  • Чтение документации (возвращаемое значение чтения / записи не просто является ошибочным условием, оно также представляет количество байтов, прочитанных / записанных)
3 голосов
/ 31 июля 2011

Мой предыдущий ответ был ошибочным. Я проверил ваши программы и вот результаты.

  • Если я запускаю оригинальный клиент, я получаю 0m7.763s
  • Если я использую буфер в 4 раза больше, я получаю 0m5.209s
  • С буфером 8 раз как оригинал я получаю 0m3.780s

Я только изменил клиента. Я подозреваю, что если вы также смените сервер, вы можете снизить производительность.

Тот факт, что я получил совершенно другие результаты, чем вы (0m7.763s против 9578ms), также предполагает, что это вызвано количеством выполненных системных вызовов (поскольку у нас разные процессоры ..). Чтобы выжать еще больше производительности:

  • Использовать скаттер-ввод / вывод (readv и writev)
  • Используйте механизмы нулевого копирования: splice(2), sendfile(2)
3 голосов
/ 31 июля 2011

Вы можете использовать strace -f iperf -s localhost, чтобы узнать, что iperf делает по-другому.Кажется, что он использует значительно большие буферы (131072 байт с 2.0.5), чем вы.

Кроме того, iperf использует несколько потоков.Если у вас 4 ядра ЦП, использование двух потоков на клиенте и сервере приведет к примерно удвоенной производительности.

1 голос
/ 31 июля 2011

Если вы действительно хотите получить максимальную производительность, используйте mmap + splice/sendfile, а для локальной связи используйте сокетные потоковые сокеты Unix (AF_LOCAL).

...