如何在TCP服务器端与多个客户端保持消息发送顺序

3
我有两台电脑通过1Gbps直连以太网线连接。其中一台作为TCP服务器,另一台作为TCP客户端。现在我想在这两台电脑之间实现最大可能的网络吞吐量。
我尝试了以下选项: 在PC-1上创建多个使用不同端口号的客户端,连接到TCP服务器。创建多个客户端的原因是为了增加网络吞吐量,但是我在这里遇到了一个问题。

setup

我有一个事件缓冲队列需要发送到服务器。其中会有多个具有相同事件编号的消息。服务器必须获取所有消息,然后根据事件编号对消息进行排序。每个客户端现在从并发队列中出队消息并发送到服务器。发送完毕后,客户端再次重复相同的过程。我已经在客户端上设置了约束条件,即在发送带有事件1标签的所有消息之前,不会发送事件2。因此,我看到发送的事件顺序是正确的。TCP服务器不断从所有客户端接收。
现在让我们来看看问题:服务器以稍微随机的方式接收数据,如图所示。在一段时间后,两个连续事件之间的随机性变得更加严重。我认为这种随机行为是由于并行工作线程执行IO完成回调引起的。
使用的技术:F#套接字异步和SocketEventArgs。
我尝试的解决方案是:不是允许在服务器端从所有客户端接收,而是尝试轮询具有挂起数据的下一个可用客户端,然后可以确保正确的顺序,但其性能根本无法与以前的方法相比。

enter image description here

我希望能够按照客户端发送的顺序(或者近似顺序,但不包括非确定性随机)接收数据。有没有办法既保留顺序又提高吞吐量?如何实现在两台电脑之间实现接近100%的网络吞吐量?

4
TCP是一种在IP协议之上分层的网络协议。TCP的目的是保证发送的数据包能够被正确接收。如果有一个数据包丢失了(即使在最好的条件下也会发生),它会被重新发送。这意味着你不能保证所发送的数据包的顺序被保留。如果你需要保证数据包的顺序,你需要使用另一种建立在TCP之上的协议(但这会降低你的吞吐量)。 - Romano Zumbé
3
似乎将客户端分成三个进程是导致大部分问题的原因;我不明白这样做应该如何帮助。肯定一个进程可以发送与三个进程相同数量的数据?然后您将在排序方面遇到更少的问题。也许在这种情况下使用某种流协议会更有用? - JeffUK
5
TCP已经保证了单个连接上的顺序。这里的问题似乎在于使用了多个TCP连接。 - TheInnerLight
1
我同意其他评论者的看法,问你为什么认为这种设计会在任何方面提高吞吐量。如果你只处理单个网络连接,添加客户端只会增加争用,很可能会使它变得更慢,而不是更快。如果你有多个网络连接,你可以使用“多路径”实现,但是...那将会更加复杂,需要客户端将数据解复用到多个路径上,然后服务器在接收时重新集成数据。数据将需要包括序列号来完成此操作。 - Peter Duniho
2
如何在两台PC上实现接近100%的网络吞吐量?编写专门用于此目的的软件。CPU和内存比网络连接更快。如果您的应用程序没有饱和线路,那么这是您的应用程序的问题,如果您需要有序传递数据,则最合适的解决方案不是运行多个实例 - 这只会创建更多问题。修复根本原因,即您无效的TCP代码。使用异步I/O、缓冲、线程。不要使用多进程。 - Jeroen Mostert
显示剩余8条评论
1个回答

0

正如其他评论中指出的那样,如果您想使用TCP,则单个TCP连接可能会为您提供最高的吞吐量。

您可以通过UDP实现略微(真的很小)更高的吞吐量,但是您需要重新创建TCP免费提供给您的所有好处。

如果您想要双向高容量高速吞吐量(而不是一次仅有一个方向的高容量),那么每个方向一个连接可能更容易处理,但我没有那么多的经验。

设计提示

您应该保持连接开放。如果没有其他通信,则客户端将需要定期询问“您还在那里吗?”(经过再次思考,我意识到这样做的唯一目的是允许快速响应和服务器启动消息事务的可能性。因此,我对其进行了修订:至少保持连接开放以进行完整的事务。)

此外,您应该将大型消息拆分为一定大小的消息块。在本地网络上,每个块发送的字节数最好控制在最大八进制数、十六进制数、三十二进制数或六十四进制数内。可以尝试不同的大小。自Windows 3以来,建议的最大大小至少是最优的。您需要使用某种协议,其中一个块由固定头(通常是用于检查和重新同步的魔术数字,还有一个用于检查和分析的块编号以及总数据包长度)后跟数据组成。
您可以通过压缩(通常是低速快速压缩)进一步提高吞吐量-这在很大程度上取决于数据以及您所在的网络速度。
然后,通常会遇到的问题是Nagle算法的问题,我已经不记得细节了。我相信我曾经通过对每个发送的块进行确认来克服这个问题,并且我认为通过这样做,您可以满足设计要求,从而避免等待最后几个字节。但请搜索一下相关信息。

1
Nagle算法对于总吞吐量并不重要,只影响延迟。它限制了“部分满缓冲区”发送的频率 - 满缓冲区总是立即发送。 - Luaan
@Bent Tranberg,我发现使用多个TCP流发送数据比单个TCP流具有更好的吞吐量。原因可能是如果接受多个TCP客户端,则服务器端具有更多的接收缓冲区,因此可以在接收方保留更多的数据并保持线路繁忙。现在的问题是,我需要在不影响性能的情况下同步接收方的数据。 - Mahesh
“你冒着等待很长时间的风险,甚至在理论上可能无限期地等待最后几个字节到来。” —— 不,你不会。 Nagle算法最多只会等待数百毫秒。它不会无限期等待。禁用它可能导致数据以不完整的缓冲区发送,从而增加网络开销并降低吞吐量。 - Peter Duniho
“你可以通过使用UDP协议来实现略微(真的只是微不足道的)更高的吞吐量” - 这仅适用于数据丢失可以被接受的情况下。而且有很多这样的情况。但在这种情况下并非如此,TCP协议既被设计又被实现为优化流媒体的吞吐量。 - Peter Duniho
你需要一种协议,并且要包含一个固定头部的块——但使用TCP不需要。 TCP保证排序,无论你如何拆分数据,到达另一端时它只是一个流。你可以使用1字节缓冲区,远程端点可以使用10K缓冲区,反之亦然。每个端点按适合该端点的缓冲区大小处理流。 - Peter Duniho
显示剩余6条评论

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