gpt4 book ai didi

networking - 使用“待发送”队列和其他设计问题限制TCP发送

转载 作者:行者123 更新时间:2023-12-01 00:01:07 25 4
gpt4 key购买 nike

这个问题是我最近几天问过的另外两个问题的结果。
我正在创建一个新问题,因为我认为这与我对如何控制发送/接收流程的理解中的“下一步”有关,而我尚未得到完整的答案。
其他相关问题是:
An IOCP documentation interpretation question - buffer ownership ambiguity
Non-blocking TCP buffer issues

总之,我正在使用Windows I / O完成端口。
我有几个线程处理来自完成端口的通知。
我相信这个问题是与平台无关的,并且将具有与在* nix,* BSD,Solaris系统上执行相同操作一样的答案。

因此,我需要拥有自己的流量控制系统。精细。
所以我发送了很多。我如何知道何时开始排队发送,因为接收方限制为X数量?

让我们举个例子(最接近我的问题):FTP协议。
我有两个服务器;一个在100Mb链路上,另一个在10Mb链路上。
我命令一个100Mb的文件发送到另一个(10Mb链接的文件)一个1GB的文件。它的平均传输速率为1.25MB / s。
发送方(100Mb链接的发送方)如何知道何时暂停发送,因此较慢的发送方不会被淹没? (在这种情况下,“待发送”队列是硬盘上的实际文件)。

另一种询问方式:
我可以从远端收到“保留您的发送”通知吗?它是内置在TCP中还是需要我执行的所谓“可靠网络协议”?

我当然可以将发送限制为固定的字节数,但这对我来说听起来并不正确。

再说一次,我有一个循环,其中有许多发送到远程服务器的循环,在某个时刻,我将不得不确定是否应该对发送进行排队,或者可以将其传递给传输层(TCP)。
我怎么做?你会怎么做?当然,当我从IOCP收到完成发送的通知时,我将发出其他挂起的发送,这很清楚。

与此相关的另一个设计问题:
由于我要在发送队列中使用自定义缓冲区,并且在到达“发送完成”通知后,这些缓冲区将被释放以供重用(因此不使用“ delete”关键字),因此,我必须使用在那个缓冲池上的相互排斥。
使用互斥锁会使事情变慢,所以我一直在想;为什么每个线程都没有自己的缓冲池,因此至少在获取发送操作所需的缓冲区时访问它就不需要互斥体,因为它仅属于该线程。
缓冲池位于线程本地存储(TLS)级别。
没有相互池意味着没有锁,意味着更快的操作BUT也意味着应用程序使用了更多的内存,因为即使一个线程已经分配了1000个缓冲区,另一个正在发送并且需要1000个缓冲区来发送内容的线程也需要分配这些都是自己的。

另一个问题:
假设我在“待发送”队列中有缓冲区A,B,C。
然后,我收到一个完成通知,告诉我接收者从15个字节中提取了10个。我应该从缓冲区的相对偏移量重新发送,还是由TCP为我处理,即完成发送?而且,如果可以的话,我可以确保该缓冲区是队列中“下一步要发送”的缓冲区吗,还是例如缓冲区B?

这是一个很长的问题,我希望没有人受到伤害(:

我很乐意看到有人花时间在这里回答。我保证我会为他加倍投票! (:
谢谢你们!

最佳答案

首先:我将作为单独的问题提出这个问题。您更有可能以这种方式获得答案。

我已经在我的博客中谈到了大部分内容:http://www.lenholgate.com,但是既然您已经给我发送了电子邮件,说您已经阅读了我的博客,那么您知道...

TCP流控制问题是这样的,因为您要发布异步写入,并且这些异步写入都将使用资源,直到它们完成为止(请参见here)。在写挂起期间,需要注意各种资源使用问题,而使用数据缓冲区是其中最不重要的问题。您还将用完一些非页面缓冲的池,这是一种有限的资源(尽管在Vista和更高版本中,可用空间要比以前的操作系统多得多),而且在写操作期间还将页面锁定在内存中,并且操作系统可以锁定的页面总数的限制。请注意,非页面缓冲池的使用情况和页面锁定问题在任何地方都没有得到很好的记录,但是一旦您碰到它们,就会开始看到ENOBUFS写入失败。

由于这些问题,未控制的写入数量不受控制是不明智的。如果您要发送大量数据,并且没有应用程序级别的流控制,则需要注意的是,如果发送数据的速度快于连接另一端可以处理的速度,或者快于链接速度,然后由于TCP流控制和窗口问题,您的写操作将花费更长的时间,因此您将开始消耗大量上述资源。阻塞套接字代码不会带来这些问题,因为当TCP堆栈由于流控制问题而无法再写入时,写入调用只会阻塞。使用异步写入,写入完成,然后挂起。使用阻塞代码,阻塞将为您处理流控制。使用异步写入,您可能会继续循环运行,并且越来越多的数据正等待TCP堆栈发送...

无论如何,因此,对于Windows上的异步I / O,您应该始终具有某种形式的显式流控制。因此,您可以使用ACK将应用程序级流控制添加到协议中,以便知道数据何时到达另一端,并且一次只能允许一定数量的未完成交易,或者如果您不能添加到在应用程序级别协议中,您可以使用写入完成来驱动事物。诀窍是允许每个连接具有一定数量的未完成写入完成,并在达到极限后将数据排队(或只是不生成数据)。然后,当每个写入完成时,您可以生成一个新的写入。

恕我直言,关于合并数据缓冲区的问题是您现在的过早优化。到系统正常运行的位置,并且已经对系统进行了概要分析,并发现缓冲池上的争用是最重要的热点,然后解决这个问题。我发现每个线程的缓冲池不能很好地工作,因为线程之间的分配和释放的分布往往不如您需要的那样平衡。我已经在博客中谈到了更多内容:http://www.lenholgate.com/blog/2010/05/performance-comparisons-for-recent-code-changes.html

关于部分写入完成(您发送100个字节,然后返回完成并说您只发送了95个)的问题实际上在IMHO中不是问题。如果您到达这个位置并拥有多个未完成的写操作,那么您将无能为力,随后的写操作可能会正常工作,并且您期望发送的字节会丢失;但是a)我从来没有见过这种情况发生,除非您已经遇到了上面我详细介绍的资源问题,并且b)如果您已经在该连接上发布了更多写入信息,那么您将无能为力,因此只需中止该连接-请注意,这是为什么我总是将网络系统配置在将要运行的硬件上,并且我倾向于在我的代码中设置限制,以防止曾经达到操作系统资源限制(在Vista之前的操作系统上,不良的驱动程序通常会蓝屏,如果可以的话)不要使用非分页池,因此如果您不注意这些细节,可以放下一个盒子。

请下次再回答其他问题。

关于networking - 使用“待发送”队列和其他设计问题限制TCP发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3034047/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com