5

我想创建一个 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 GBit/s。然后我做了我自己的 C++ 服务器/客户端实现,你可以在这里找到完整的代码:https ://gist.github.com/1116635

在那个代码中,我基本上用每个读/写操作传输一个 1024 字节的 int 数组。所以我在服务器上的发送循环如下所示:

   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 GBit/s:

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

我在哪里失去带宽,我做错了什么?同样,完整的代码可以在这里看到:https ://gist.github.com/1116635

任何帮助表示赞赏!

4

4 回答 4

5
  • 使用更大的缓冲区(即减少库/系统调用)
  • 使用异步 API
  • 阅读文档(read/write的返回值不仅仅是一个错误条件,它还代表了读/写的字节数)
于 2011-07-31T09:44:00.413 回答
3

您可以使用strace -f iperf -s localhost来找出 iperf 的不同之处。似乎它使用的缓冲区比您大得多(131072 字节大,2.0.5)。

此外,iperf使用多个线程。如果您有 4 个 CPU 内核,在客户端和服务器上使用两个线程将导致性能大约翻倍。

于 2011-07-31T09:50:49.080 回答
3

我之前的回答是错误的。我已经测试了你的程序,结果如下。

  • 如果我运行原始客户端,我会得到0m7.763s
  • 如果我使用 4 倍大的缓冲区,我会得到0m5.209s
  • 我得到的缓冲区是原始缓冲区的 8 倍0m3.780s

我只换了客户端。我怀疑如果您还更改服务器,可能会压缩更多性能。

我得到的结果与你完全不同的事实(0m7.763svs 9578ms)也表明这是由执行的系统调用数量引起的(因为我们有不同的处理器......)。为了获得更多性能:

  • 使用 scater-gather I/O (readvwritev)
  • 使用零拷贝机制:splice(2),sendfile(2)
于 2011-07-31T10:06:45.817 回答
1

If you really want to get max performance use mmap + splice/sendfile, and for localhost communication use unix domain stream sockets (AF_LOCAL).

于 2011-07-31T10:48:51.230 回答