如何利用套接字利用100%的网络带宽?

时间:2014-09-06 15:25:51

标签: c sockets networking bandwidth

我有一台服务器和一台客户端。它们在不同的服务器上工作。两台服务器都有两个1000M网络适配器

我在服务器和客户端都使用 tcp阻塞套接字

服务器

接受套接字后,将启动一个新线程来处理请求。它的工作方式如下:

while(1) {
    recv();  /* receive a char */
    send();  /* send a line */
}

客户端只需向服务器发送一个字符,服务器就会向客户端发送一行文本。文本的长度约为200。

该行已预先加载到内存中。

客户端

客户端使用不同的线程连接到服务器。连接后,它将像:

while(1) {
    send();  /* send a char */
    recv();  /* receive a line and  */
}

带宽使用

当我在客户端使用100个线程时(结果几乎相同),我在服务器中获得此网络流量:

tsar -l -i 1 --traffic

结果:

Time              -------------traffic------------
Time               bytin  bytout   pktin  pktout
06/09/14-23:12:56   0.00    0.00    0.00    0.00
06/09/14-23:12:57  63.4M  155.3M  954.6K  954.6K
06/09/14-23:12:58   0.00    0.00    0.00    0.00
06/09/14-23:12:59  60.1M  147.3M  905.4K  905.4K
06/09/14-23:13:00   0.00    0.00    0.00    0.00
06/09/14-23:13:01  57.5M  140.8M  866.5K  866.4K

sar -n DEV 1

11:20:46 PM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
11:20:47 PM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:20:47 PM      eth0 478215.05 478217.20  31756.46  77744.95      0.00      0.00      0.00
11:20:47 PM      eth1 484318.28 484318.28  32162.05  78724.16      0.00      0.00      1.08
11:20:47 PM     bond0 962533.33 962535.48  63918.51 156469.11      0.00      0.00      1.08

问题:

理论上,(bytin + bytout)的最大值可以是256M。我该如何存档?

任何帮助都会很棒,谢谢。

2 个答案:

答案 0 :(得分:4)

实际上,在几个层中存在一些开销。 1Gbits / sec以太网在应用程序方面并不意味着那么多(但我估计最多90%)。经验法则是sendrecv相当大的数据大小(例如至少几千字节)。发送或接收几百个字节是低效的。问题肯定是操作系统特定的(我在想Linux)。

回想一下,根据定义,TCP不是数据包的传输,而是字节流。阅读TCP wikipage。你应该避免send - 或recv - 几个字节,甚至一百个字节。每次尝试send数千个字节。当然,接收方上的单个recv(通常)不对应于发射器侧的单个send,反之亦然(特别是如果您在发送和接收计算机之间有一些路由器;路由器;可以拆分或合并网络数据包,因此您无法确保在发射器中每个recv的接收器上有一个send

Gigabit Ethernet希望Jumbo Frames接近9000字节。您可能希望send的数据缓冲区略低于此值(因为IP和TCP的各种开销),所以请尝试8K字节。

send(2)手册页提到tcp(7)MSG_MORE标记。你可以小心使用它。另请参阅this

syscalls(2)还有一些开销。我很惊讶你能够每秒赚到一百万。这个开销是另外一个原因是缓存大量的传出和传入数据(例如每个8192,16384或32768字节;你需要进行基准测试才能找到最好的数据)。如果内核更喜欢页面对齐的数据,我也不会感到惊讶。所以也许尝试让你的缓冲区对齐到4096字节(例如使用mmap(2)posix_memalign(3) ...)

如果您关心性能,请不要将send(2)用于小字节数。至少更改您的应用程序,以便在每个send系统调用时发送超过几千字节(例如4K字节)。对于recv(2),传递至少4千字节的缓冲区。因此sendrecv单个字节或一百个字节的行是低效的。您的应用程序应缓冲此类数据(并可能将数据拆分为“应用程序消息”...)。有些库正在这样做(比如0MQ ...),或者至少使用分隔符(也许是换行符)终止每条消息,这样可以简化将接收缓冲区拆分为几个传入的应用程序消息。

我的感觉是你的应用程序效率低下且有问题(可能在其他网络上运行不好,例如两台计算机之间有一些路由器)。您需要重新设计并重新编写应用程序的某些部分!您需要缓冲,并且需要管理应用程序消息 - 拆分和连接它们....

Yous应该在多个网络上测试您的应用程序,特别是通过ADSL和wifi以及可能的远程网络(然后您会发现sendrecv不匹配“)。

答案 1 :(得分:2)

根据我的数学,你相对接近饱和链接。

据我所知,这是流量的一秒。

Time              -------------traffic------------
Time               bytin  bytout   pktin  pktout
06/09/14-23:12:57  63.4M  155.3M  954.6K  954.6K

通过以太网发送的TCP数据包有82字节的开销(42个以太网,20个IP,20个TCP),因此接收的数据量为(954.6k * 80 + 63.4M)* 8位,总计1.1G。

我认为对于如此大量的数据包,物理介质的协商会涉及额外的开销。由于链路利用率约为50%,如果有一个额外的延迟小到(1s / 954.6k)* 50%= 500 ns(半个微秒!),那么你已经考虑了额外的延迟。 500 ns是光线行进150米所需的时间,这并不是那么远。