我想知道在检查传入数据时(异步)最有效的方法。假设我有500个连接。我有3个场景(我能想到):
我已经将情况编码为1和2,但我不确定使用哪种情况。对不起,如果我有点不清楚。
由于
答案 0 :(得分:3)
FD_SETSIZE
通常为1024,因此您可以一次检查所有500个连接。然后,您只会对那些已准备好的执行两次recv
次呼叫 - 例如,对于一个非常繁忙的系统,每次都会有六个这样的呼叫。使用其他方法,您需要大约500个系统调用(在不准备好的数百个套接字上执行的大量“失败”recv
或select
调用在任何给定的时间! - )。
此外,使用方法1,您可以阻止,直到至少有一个连接 准备就绪(在这种情况下没有开销,这在不那么繁忙的系统中并不罕见) - - 使用其他方法,你需要进行“轮询”,即搅拌,持续不断地将大量的CPU烧掉,没有任何好的目的(或者,如果你在每次循环之后睡了一会儿)检查,然后你会有一个延迟响应尽管系统没有忙 - eep! - 。)。
这就是为什么我认为轮询是反 - 模式:经常使用,但仍具有破坏性。有时候你绝对没有其他选择(这基本上告诉你,你必须与设计非常糟糕的系统进行交互 - 唉,有时候你在做这个不完美的生活中必须! - ),但是当体面的替代确实存在,然而进行投票确实是一个非常糟糕的设计实践,应该避免。
答案 1 :(得分:3)
你可以简单地在3场景中进行一些效率模拟:
情景A(0/500传入数据)
select()
select()
recv()
情景B(250/500传入数据)
select()
+(500 recv()
)select()
+(500 recv()
)recv()
**假设跳过没有缓冲区大小的套接字@没有传入数据
答案显而易见:)
答案 2 :(得分:1)
...检查时效率最高 传入数据(异步)。让我们 说我有500个连接。我有3个 场景(我能想到):
使用select()检查FD_SETSIZE 一次插座,然后迭代 所有这些都是为了接收数据。 (这不需要两个电话 返回每个套接字的recv? MSG_PEEK分配缓冲区然后再次recv()它将与#3相同
我相信你只是用目前连接的描述符仔细构建你的fd集......?然后迭代该集合,并仅针对具有读取或异常/错误条件的那些(后者区别在于BSD和Windows实现之间)发出recv()。虽然它在功能上是可以的(并且在概念上可以说是优雅的),但在大多数真实世界的应用程序中,您不需要在恢复之前查看:即使您不确定消息大小并且知道您可以从缓冲区查看它,应该考虑一下你是否可以:
使用select()一次检查一个套接字。 (这不会像#3那样吗?它需要两次调用recv。)
一点也不好。如果你保持单线程,你需要在select上放一个0超时值,并通过listenig和client描述符疯狂地旋转。非常浪费CPU时间,并且会大大降低延迟。
一次使用recv()和MSG_PEEK一个套接字,分配缓冲区然后再次调用recv()。这会不会更好,因为我们可以跳过select()的所有调用?或者是一个recv()调用过多的开销?
(忽略尝试避免使用MSG_PEEK更好) - 你怎么知道MSG_PEEK或recv()的哪个套接字?再次,如果你是单线程,那么你要么阻止第一次peek / recv尝试,要么你使用非阻塞模式,然后通过所有描述符疯狂旋转,希望窥视/ recv将返回一些东西。浪费的。
所以,坚持1或转移到多线程模型。对于后者,最简单的方法是让监听线程循环调用accept,每次accept产生一个新的客户端描述符时,它应该生成一个新线程来处理连接。这些客户端连接处理线程可以简单地阻塞在recv()中。这样,操作系统本身就会响应事件来监视和唤醒线程,您可以相信它会合理有效。虽然这个模型听起来很简单,但你应该知道多线程编程还有很多其他的复杂问题 - 如果你还不熟悉它,你可能不想尝试在套接字I / O的同时学习它。 / p>