2010-01-06 137 views
3

我不明白在等待调用recv()之后,在非阻塞套接字上调用recv()与阻塞套接字之间的区别是什么,在select返回之后它已准备好读取。无论如何,在我看来,像这样的阻塞套接字永远不会阻塞。
此外,我听说一个使用非阻塞套接字的模型是在经过一段时间后,尝试对它们进行调用(recv/send/etc),而不是使用select之类的东西。这种技术看起来很慢并且比较浪费,比如使用类似select的方法(但是如上所述,我根本没有达到非阻塞的目的)。这在今天的网络编程中很常见吗?带选择的非阻塞套接字

回答

1

select,poll,epoll,kqueue等设施目标多套接字/文件描述符处理方案。想象一下,一个带有数百个同时连接的套接字的重载Web服务器。你怎么知道什么时候read以及什么套接字没有阻塞一切?

0

如果您在非阻塞套接字上调用read,如果自上次调用read以来没有收到任何数据,它将立即返回。如果您只有read,并且您想等到有数据可用时,则必须busy wait。这浪费了CPU。

pollselect(和朋友)允许你睡觉,直到有数据要读取(或写入,或收到信号等)为止。

如果您正在做的唯一事情是在该套接字上发送和接收,那么您可能只需使用非阻塞套接字。当你有其他事情要做的时候,异步是很重要的,例如更新GUI或处理其他套接字。

0

对于你的第一个问题,在这种情况下没有任何区别。唯一的区别是当没有什么可读的时候他们会做什么。既然你在调用recv()之前检查它,你将看不到任何区别。

对于第二个问题,我在所有库中看到的方式是使用select,poll,epoll,kqueue来测试数据是否可用。选择方法是最老的,从性能角度来看最不理想(特别是对于管理大量连接)。

+0

'select'可以指示一个套接字是可读的,但是当它去读取它时,它没有可用的数据。这是一个非常有边缘的情况,但它可能发生在像校验和不好的数据包一样的情况下(只有当应用程序读取数据时才会检查它)。 – caf 2010-01-11 03:44:39

3

对于执行大容量I/O的所有不同选项(称为The C10K Problem)都有很好的概述。它有很多不同的选择,至少在2006年

从它引用的一个相当完整的调查显示,在非阻塞套接字使用select的话题:

注:这是特别重要的是要记住,来自内核的准备就绪通知只是一个提示;当您尝试从中读取文件描述符可能不会准备好。这就是为什么在使用准备就绪通知时使用非阻塞模式非常重要。

是的,你可以使用非阻塞套接字,然后有一个循环,等待如果没有准备好,但相比使用类似select或更现代的替代品(epoll的一个相当浪费,kqueue等)。我想不出任何人真的想要这样做的原因;所有select类似的选项都有能力设置超时,所以你可以在一段时间后唤醒来执行一些常规操作。我想,如果你正在做一些相当CPU密集的事情,比如运行一个视频游戏,你可能不想睡觉,而是保持计算,同时使用非阻塞套接字定期检查I/O。

+2

当需要低延迟时,这种繁忙的循环是相当普遍的,浪费周期被一些$$$覆盖(阅读 - 金融业:)。这个想法基本上不是让内核在syscall内部休眠,因此至少关闭两个上下文切换。 – 2010-01-07 20:35:22

+0

够公平的。所以你可能会这样做有一些原因,但是对于大多数应用程序,你通常希望使用'select'循环。 – 2010-01-07 21:56:43