高性能udp服务器。阻止还是非阻塞? C

时间:2010-02-10 04:17:32

标签: c sockets udp

我一直在为udp做很多关于阻塞和非阻塞套接字的阅读,但我很难理解一个优点而不是另一个。互联网上的绝大多数评论似乎都表明非阻塞性更好,但对于哪些情况下它们会更好,并不是非常具体,而且我发现没有任何参考资料,只要阻止是首选。我对这个问题的希望是,社区可能会对这个问题有所启发。

关于我自己的问题集的一些背景知识,因此答案可能会特别适用于问题的一般性质。我有一个udp服务器,我写的将在本地局域网上有40个连接,从而可以流入恒定的数据流。数据速率将达到250MB / s avg,峰值达到500 + Mb / s,平均值数据报大小约为1400字节。数据报的处理很轻,但由于大量的msgs效率和性能是高优先级,以防止丢包。

因为我无法真正找到类似于这个特定问题集的内容的任何上下文信息,所以我必须根据我能够收集的关于阻塞与非阻塞的内容进行一些猜测。我将用我目前的假设结束这个,然后打开你的输入。基本上,因为这将是每个连接上几乎恒定的数据包流,我认为阻塞套接字会更好,因为任何recv函数实际花费阻塞的时间与使用事件相比非常非常小基于模型,在异步模式下会有大量的触发器。我觉得我的真正的问题集很可能是我计划用于从套接字读取的40个线程的优先级管理...确保每个获得它们的cpu时间份额。我的方法和想法可能不正确,所以我希望并且非常感谢社区可以帮助阐明这个问题。

问候,吉姆。

〜编辑〜

虽然我担心线程设计将如何影响/整合阻塞/非阻塞问题。我真的非常关心应该从我的问题集的角度来看待阻塞/非阻塞。如果线程确实成为一个问题,我可以使用线程池解决方案。

〜EDIT2〜

首先,想说到目前为止你的回答是坦克。你们中的一些人已经提到过具有这么多套接字的单线程/套接字模型可能是一个坏主意,我承认我自己是解决方案。然而,在nikolai响应中的一个链接中,作者讨论了一个单线程/套接字模型,并链接到一个非常有趣的论文,我认为我将链接到这里,因为它消除了我对线程与事件有关的很多神话基于模型:why events are a bad idea

享受。

4 个答案:

答案 0 :(得分:5)

不是答案,只是一些链接,如果你的书签中还没有这些链接:

Dan Kegel的

The C10K problem
杰西达西的High-Performance Server Architecture
高级轮询API:epoll(4)kqueue(2)

编辑:

虽然听起来很愚蠢,但我完全错过了你正在使用UDP,所以......

由于UDP中没有协议级别的连接,除非必须在不同的端口上工作, 您在服务器上不需要40个套接字 即可。只需 一个 UDP“服务器”套接字即可为所有客户端提供服务。您可以阻止这一个套接字,只需确保套接字接收缓冲区足够大,以适应流量峰值,并且不会花太多时间处理每次读取。

答案 1 :(得分:2)

我不知道阻塞或非阻塞具有显着的性能优势;这是一个关于网络I / O事件循环想要做什么事情的问题:

  • 如果您的网络I / O线程唯一要做的就是在单个套接字上侦听传入的UDP数据包,那么阻止I / O可能会正常工作并且更容易编程。

  • 如果您的网络I / O线程需要处理多个套接字,那么阻塞I / O会出现问题,因为如果它在套接字A上阻塞,它将不会被唤醒以处理到达的数据插座B,反之亦然。在这种情况下,非阻塞I / O成为首选,因为您可以在select()或poll()中进行阻塞,只要数据在任何被监视的套接字上可用,它就会返回。

请注意,即使在非阻塞情况下,您也不希望在数据包之间进行忙循环,因为在线程A中烧掉CPU周期意味着它们不可用于线程B,这会损害性能。因此,如果你没有在recv()中阻塞,请确保在select()或poll()中阻塞。

答案 2 :(得分:2)

  • 使用阻止IO时,在程序中的某个位置,您应该有一个轮询或选择等待任何文件句柄(在您的情况下为套接字)中的数据。因为如果你在没有确保数据准备就绪的情况下读取你的任何一个fh它会阻塞,程序将停止管理其他套接字。为了避免这种情况并保持程序使用阻塞IO的简单程序通常用每个socket / fh的一个线程编写,因此无需轮询或选择。

  • 如果您使用非阻塞IO,您的程序将运行并检查数据到达,因为它看到每次读取。无需民意调查或选择。该程序仍然可以非常简单,并且不需要为此特定目的使用线程。

我认为最有效的方法是使用poll或select来同时管理多个IO(它可以是线程之间分割的所有文件句柄的子集,如果您愿意的话)。它比没有轮询或选择的非阻塞IO更有效,因为这种方法基本上试图在大多数时间内无用地读取每个套接字并且有成本。这三者之间最糟糕的方法是对每个线程使用阻塞IO和一个fh,因为与返回的WOULDBLOCK或轮询的读取相比,线程管理的成本很高。

这就是说,非阻塞IO还有另外一个优点:你的程序除了IO之外还可以进行计算,当阻塞等待IO时你无法做到。这可能会导致使用非阻塞IO的poll / select或使用较小的超时,或者甚至使用专用于IO和其他线程的小型专用线程来处理更多计算密集型部件或程序。

在某些情况下,您可能也没有任何选择。我碰巧不得不等待通过NFS挂载的文件句柄中的数据。在这种情况下,尝试设置非阻塞IO是没用的,因为NFS层在内部使用阻塞IO ...

您也可以考虑使用异步IO。它非常高效,您的程序变为“事件驱动”。这对于Windows系统来说很常见,我还没有看到Linux的异步IO的当前开发状态​​。上次我检查了一些人在哪里工作时将异步IO添加到内核API,但我不知道它是否稳定或是否已达到主流内核。

答案 3 :(得分:0)

我不太确定40个套接字使用40个线程是一个好主意...当然,当你有少量套接字时,每个套接字使用一个线程是有意义的,但是有这么多线程只是要求线程饥饿,死锁和错过的数据包。

至于阻止与非阻塞,请记住阻塞可能相对昂贵...虽然在我看来它更容易使用。异步触发器等可能总体上更快,然后必须阻塞/唤醒线程。