在C ++应用程序中,为了实现最佳使用,要打开的并行套接字/ TCP连接数量是多少?

5
我正在开发一个C++应用程序,目前使用C sockets在对等方之间传输数据。有n个对等方,所有对等方都运行相同的代码。在应用程序逻辑中,任何对等方都可能需要向任何其他对等方传输(可能很大的)数据,因此首先在所有可能的对等方之间打开连接。要求应用程序逻辑和(可能很大的)数据网络传输速度尽可能快。
目前,在任意两个对等方之间(例如A和B),应用程序打开两种类型的连接 - 一种是A是服务器,B是客户端,反之亦然。这样做可能是为了如果A和B需要并发地相互传输数据,则整个过程可以比只从A到B具有一种连接类型更快地完成。对于每种连接类型(例如A是服务器,B是客户端),应用程序然后打开3个TCP连接(使用C-sockets)。但是,它目前的编码方式只使用其中一个这些3个连接。
看到这一点,我开始想知道如何最优地利用N个打开的连接,也许可以使用轮询或某种策略将数据分块并同时传输。但是,有多少个并行TCP连接应该打开以及这些连接之间应该使用什么策略不清楚。这个答案还取决于哪些因素?例如,如果我打开了1000个TCP连接,有什么危害?(忽略系统约束,如用完端口等)
如果有人可以说明如何使应用程序利用多个并行TCP连接最具性能,那将是很好的。快速的谷歌搜索会导致几篇研究论文,但我也对例如Web浏览器如何解决此问题感兴趣。
谢谢!
更新:与一些更了解TCP的人交谈后,我对情况有了更好的了解。首先,我的前提是在A和B之间打开两种类型的连接(A是客户端,B是服务器,反之亦然)将有助于增加网络吞吐量似乎是错误的。在A和B之间打开一种类型的TCP连接就足够了。这取决于数据报是否能够同时从A到B和反之亦然。我发现这个链接很有用:TCP是双向还是全双工的?
此外,为了充分利用可用带宽,最好打开多个TCP连接。我发现这个非常相关的链接:TCP是否可以通过多个连接实现更高的传输速率? 但是,仍然存在打开多少此类连接的问题。如果有人能回答这个问题就太好了。

看一下这里的代码(https://github.com/Michael-Buzgaru/WhatsChatRoom),了解`select()`函数的工作原理。 - Michi
1
更多的TCP连接会让情况变得更糟。这意味着需要跟踪和修改更多的状态,通常情况下需要两个数据包来完成一个数据包的工作。(例如,如果ACK是针对不同的TCP连接,则无法将其附加在数据上,但如果它们是相同的,则可以这样做。)这将意味着需要更多的工作来发现延迟和带宽,更多的慢启动实例等等。 - David Schwartz
2个回答

2
当在两个主机之间传输数据时,使用多个TCP套接字不太可能获得任何显著的吞吐量优势。通过适当的编程,单个TCP连接可以同时饱和线路速度的双向带宽(即它可以进行全双工/双向传输)。将数据分散到多个TCP连接中只会增加开销;在最好的情况下,每个N个连接将以单个连接的1/N的速度传输(在实际情况下,由于额外的数据包头、带宽争用等原因,速度甚至更慢)。
然而,使用多个TCP流可能会产生一些潜在的(轻微)好处——这种好处只在传输在流A中传输的数据与在流B中传输的数据在逻辑上是独立的情况下才能看到。如果是这种情况(即如果接收者可以立即使用流A中的数据,而无需等待流B中的数据先到达),那么使用多个流可以使您的数据传输对数据包丢失更加有弹性。
例如,如果流A丢失了一个数据包,那么这将导致流A必须暂停一会儿,同时重新传输丢失的数据包,但与此同时,流B的数据可能会继续流动而没有中断,因为流B是独立于流A运行的。(如果A数据和B数据都通过同一TCP流发送,那么B数据将被迫等待丢失的A数据包被重新传输,因为在TCP流中始终强制执行严格的FIFO排序)。
请注意,尽管如此,这种好处可能比您想象的要小得多,因为在许多情况下,导致一个TCP流丢失数据包的问题也会同时导致任何其他通过相同网络路径的TCP流丢失数据包。

谢谢您的回答!然而,据我所了解,为了最大限度地利用带宽,要么您应该更改TCP窗口大小,以便始终使用数据填满从A到B的链接,要么通常情况下,如果您不更改窗口大小,则具有多个流可能有助于饱和链接。请查看此链接:link - nishkr
然而,我同意你的观点,通过正确的编程(例如设置正确的窗口大小),可以通过一个TCP连接实现最佳效果。然而,增加窗口大小会带来其他意想不到的后果,例如增加缓冲区大小等。我想知道一般的网络优化应用程序是如何解决这个问题的 - 它们只使用单个连接吗?有什么想法吗? - nishkr
我不能代表大多数网络应用程序说话,但在我的应用程序中,我仅在逻辑上有意义的情况下使用多个TCP连接(例如,在与多个服务器同时通信时),并依赖于默认设置,并假定TCP堆栈实现者选择了他们认为最适合大多数常见情况的默认值(而不是试图猜测他们的决策)。这产生了对我的目的足够好的结果(例如,在本地千兆以太网LAN上的~100MB /秒)。 - Jeremy Friesner
我再次查看了我的程序,它可以进行每秒100MB的文件传输,并且我发现在该程序中将发送缓冲区和接收缓冲区大小都设置为64KB。我认为这样做不会影响修改后的TCP套接字的行为,除了导致它们分配一些额外的RAM之外,并使它们不太可能因接收缓冲区已满而必须放弃接收到的数据包,并使它们不太可能在套接字的I/O线程能够添加更多数据之前因发送缓冲区耗尽而暂停发送。 - Jeremy Friesner

1
你没有指定操作系统,所以我假设我们讨论的是Linux。 我认为你需要研究非阻塞IO,例如epoll或asio。这是目前处理多个连接的最有效和可扩展的方式。 例如,你可以从这里开始。 一些性能分析可以在这里这里找到。

1
我认为在这种情况下select()函数很有效。 - Michi
select() 在小规模应用中表现良好,但需要扩展时就不太行了。我认为 epoll 应该是默认选择。 - grungegurunge
当然,我知道异步编程和非阻塞网络调用会有所帮助。但我的问题有些不同。假设您要传输1 GB的数据,并打开一个连接,使用一个线程开始写入100 MB的数据。非阻塞IO意味着应用程序线程不会在IO调用上阻塞,而可以继续处理。但为了更好的效率,如果我知道最后100 MB的写入需要一些时间,我应该打开另一个连接并在其上开始写入另外100 MB等等。我的问题是应该打开多少此类新连接? - nishkr
我相信现代应用程序,比如浏览器,在执行非阻塞IO的同时会打开并行连接 - 它们会打开多少个连接?这也将取决于操作系统和系统参数,但从理论上讲,理想值应该是多少? - nishkr
1
多个并行连接如何提高速度?我认为浏览器使用并行连接是因为如果其中一个资源下载卡住了,它不会影响整个页面的显示。另一种情况是当远程端每个连接有带宽限制时,您可以使用并行连接来缓解这种情况,但这是非常特殊的情况。 - grungegurunge
我已通过更多的链接更新了问题。你能否请检查我发布的第二个链接:link 。这表明打开多个连接将有助于充分利用带宽,但没有回答应该打开多少个这样的连接。 - nishkr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接