我有这样的内存,当我们想通过套接字描述符使用select()时,应该事先将这个套接字设置为NONBLOCKING。应该在socket被select()调用之前设置NON-BLOCKING?
但今天,我读了一个源文件,其中似乎没有行将套接字设置为NON-BLOCKING 我的内存是否正确?
谢谢!
我有这样的内存,当我们想通过套接字描述符使用select()时,应该事先将这个套接字设置为NONBLOCKING。应该在socket被select()调用之前设置NON-BLOCKING?
但今天,我读了一个源文件,其中似乎没有行将套接字设置为NON-BLOCKING 我的内存是否正确?
谢谢!
如果提供的数据多于可以装入套接字发送缓冲区的数据,则发送()和写入()数据块。通常在select()编程中,除了select()之外,您不想阻塞任何地方,所以使用非阻塞模式。
对于某些Windows API,使用非阻塞模式确实非常重要。
这取决于。设置一个套接字非阻塞做几件事情:
使没有数据立即read()
/recv()
回报,而不是阻塞,如果没有什么可用的插座上阅读。
如果您使用的是select()
,这可能不是问题。只要你只从套接字读取select()
告诉你它是可读的,你没事。
使得write()
/send()
返回部分(或零)写入,而不是阻塞,如果没有足够的空间在内核缓冲区中可用。
这是一个棘手。如果您的应用程序是为了处理这种情况而编写的,那就太好了,因为这意味着当客户端读取缓慢时,您的应用程序不会阻塞。但是,这意味着您的应用程序需要将可写数据临时存储在其自己的应用程序级缓冲区中,而不是直接写入套接字,并有选择地将套接字写入writefds
集中。根据你的应用程序的不同,这可能是一个救星或者一个巨大的附加复杂因素。谨慎选择。
如果在套接字连接之前设置,则会在实际建立连接之前立即返回connect()
。
类似地,如果您的应用程序需要连接到可能缓慢响应而同时继续在其他套接字上响应的主机,则此功能有时很有用,但如果您不小心如何处理这些半连接的套接字。通常最好避免这种情况(只要在连接后将套接字设置为非阻塞状态(如果有的话))。
一般情况下,你不需要设置一个套接字非阻塞在select()
使用它。系统调用已经可以让你以基本的非阻塞方式处理套接字。不过,有些应用程序需要非阻塞式写入,而这正是该标志仍然需要的。
通常当你使用select()时,你正在使用它是事件循环的基础;并且在使用事件循环时,您希望事件循环仅在select()内部并且从不在其他任何地方进行阻塞。(之所以这样,是因为当它处理的任何套接字上有某事要做时,你的程序总是会醒来 - 例如,如果你的程序在socket A的recv()内被阻塞了,它会是无法处理来自套接字B的任何数据,直到它从套接字A获得一些数据才将其唤醒;反之亦然)。
因此,最好在使用select()时设置所有套接字非阻塞。这样,您的程序就没有机会在单个套接字上被阻塞,并且在相当长的一段时间内忽略其他套接字。
duskwuff有正确的想法时,他说
一般情况下,你不需要设置一个套接字非阻塞使用它在选择 ()。
如果你的内核在select()方面符合POSIX标准,这是真的。不幸的是,有些人使用Linux,这是不,作为Linux选择()手册页说:
在Linux下,选择()可能会报告套接字文件描述符为“准备 阅读”,而仍然一随后的读取块。这可能对于 示例发生在数据已到达但检查错误 校验和时被丢弃。在其他情况下, 文件描述符被虚假地报告为就绪。因此,在不应该阻塞的套接字上使用O_NONBLOCK可能会更安全 。
在2011年6月18日星期六左右,有关于lkml的讨论。一位内核黑客试图证明非POSIX合规性。他们在方便时尊重POSIX,当不符时亵渎它。
他认为“可能有两个读者,第二个会阻止。”但是,这样的应用程序缺陷是不适合的。内核预计不会阻止应用程序的缺陷。内核具有明确的职责:在select()之后的第一个read()的所有情况下,内核必须返回至少1个字节,EOF或错误;但从不阻止。至于write(),你应该总是在写之前测试套接字是否被select()所报告。这保证你可以写至少一个字节,或者得到一个错误;但从不阻止。让select()帮助你,不要盲目地写,希望你不会阻止。 Linux黑客对拐角案件等的抱怨是“我们懒得解决困难问题”的委婉说法。
假设你读取串行端口组:
分钟N;与-icanon一起,为已完成的读取设置N个字符的最小值
时间N;与-icanon,组读取的第二
分钟250时间1
Ñ十分之超时这里要的250个字符,或十分之一秒超时块。当我在非阻塞模式下在Linux上尝试这种方法时,读取每个字符都会返回,并敲击CPU。将其置于阻塞模式以获取记录的行为是必要的。
因此,在select()方法中使用阻塞模式有很好的理由,并期望您的内核符合POSIX标准。
但是,如果您必须使用Linux,Jeremy的建议可能会帮助您应对其内核缺陷。
哇,这些答案有点混乱,两个答案说套接字需要设置非阻塞,2答案说没有必要。 – misteryes
@misteryes我认为这取决于你如何严格定义“需要”。如果在select()指示它是read-for-read之后,只要在套接字上只调用recv()一次,则可以避免使用阻塞套接字,前提是recv()在该情况下不会阻塞。但是如果recv()无论如何阻塞(例如由于Trifle Menot的答案中描述的Linux“特性”),或者如果代码库中的某处后来忘记了唯一调用recv() - 一旦规则并最终调用它两次?那么你的程序可能会在recv()中被阻塞,可能会持续很长时间,否则会被冻结。 :( –