在讨论IO多路复用的时候,我们总是会看到这么一句话“当文件描述符准备就绪的时候,干嘛干嘛.....”但是这个文件描述符怎么样才算就绪了呢?相信许多朋友在面试的时候,对这句话也只是轻轻带过,如果面试官突然来一句怎么算就绪了呢? 是不是就蒙圈了?鄙人在不久前的面试的时候就碰到了这个问题。所以,这给我们启发,背八股还是得知道每个词的含义,这样才能经得起深挖。
废话不多说,我们开始讲。
本地文件
对于本地文件非常简单,当你读文件的时候,如果文件可读那就是就绪;你要写,如果文件科写,那就是就绪了。
Socket
我们使用IO多路复用的场景多是网络通信的情况下,因为会涉及到非常多的socket,这样IO多路复用的优势就体现得更明显。
(1)满足下列四个条件中的任何一个时,一个套接字准备好读。
a)该套接字接收缓冲区中的数据字节数大于等于套接字接收缓冲区低水位标记的当前大小。对这样的套接字执行读操作不会阻塞并将返回一个大于0的值(也就是返回准备好读入的数据)。我们可以使用so_RCVLOWAT套接字选项设置该套接字的低水位标记。对于TCP和UDP套接字而言,其默认值为1。 大白话就是当前缓存区的数据已经够多啦,准备就绪啦,赶紧来读我吧
b)该连接的读半部关闭(也就是接收了FIN的TCP连接)。对这样的套接字的读操作将不阻塞并返回0(也就是返回EOF)。大白话就是我准备断开连接啦,不给你发数据了,你赶紧把这些数据读了吧。
c)该套接字是一个监听套接字且已完成的连接数不为0。对这样的套接字的accept通常不会阻塞。监听套接字是服务器端用于接受新连接的。当有客户端连接请求完成三次握手,进入已连接状态时,监听套接字上就有“已完成的连接,通常来说对于已经完成的连接,accpet不阻塞。
d)其上有一个套接字错误待处理。对这样的套接字的读操作将不阻塞并返回-1(也就是返回一个错误),同时把errno设置成确切的错误条件。这些待处理错误(pending error)也可以通过指定sO_ERROR套接字选项调用getsockopt获取并清除。既然发生错误了,就没必要等待了,也可以认为是就绪了。
(2)下列四个条件中的任何一个满足时,一个套接字准备好写。
a)该套接字发送缓冲区中的可用空间字节数大于等于套接字发送缓冲区低水位标记的当前大小,并且或者该套接字已连接,或者该套接字不需要连接(如UDP套接字)。这意味着如果我们把这样的套接字设置成非阻塞(写操作将不阻塞并返回一个正值(例如由传输层接受的字节数)。我们可以使用so_SNDL.OWAT套接字选项来设置该套接字的低水位标记。对于TCP和UDP套接字而言,其默认值通常为2048。大白话就是缓冲区空间很足,快来写
b)该连接的写半部关闭。对这样的套接字的写操作将产生sIGPIPE信号。 连接关闭了,不让你写了,不阻塞你了,也可以认为是就绪
c)使用非阻塞式connect的套接字已建立连接,或者connect已经以失败告终。
d)其上有一个套接字错误待处理。对这样的套接字的写操作将不阻塞并返回-1(也就是返回一个错误),同时把errno设置成确切的错误条件。这些待处理的错误也可以通过指定RROR套接字选项调用aetsockopt获取并清除。
(3)TCP外带数据,发送异常,不阻塞,直接返回结果,也被认为是一种就绪。
注:当一个套接字发生异常,通常会被认为是既可读又可写
以上内容来自《unix网络编程》,有兴趣的朋友可以继续钻研,在第六章