linux编程中select函数用于检测一组socket上是否有事件就绪,这里的事件包括可读、可写、异常事件,其中读事件就绪是指发生以下几种情况:
1. socket内核接收缓冲区的字节数大于等于低水位标记SO_RCVLOWAT,此时可调用read或recv无阻塞的读取文件描述符,且read/recv返回值大于0。
2. TCP连接对端关闭连接,此时本端调用read或recv进行读操作,返回0。
3. 监听socket上有新的连接请求。
4. socket有未处理的错误。
写事件就绪是指发生以下几种情况:
1. socket内核发送缓冲区空闲字节数大于等于低水位标记SO_SNDLOWAT时,可以进行无阻塞的写操作,且写操作返回值大于0。
2. socket写操作被关闭(调用close或者shutdown)
3. socket使用非阻塞connect连接成功或失败。
函数签名如下:
int select(int nfds, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout);
参数说明:
nfds: 一般设置为最大fd的值加1
接下来三个参数分别表示要监听的可读/可写/异常事件的集合
最后一个参数表示超时时间,超时后select函数返回。timeval的定义如下:
struct timeval
{
long tv_sec; // 秒
long tv_usec; // 微秒
}
如果tv_sec和tv_usec都设置为0, 则select立即返回。
fd_set是一个整型数组,其中每一个bit标记一个关注的事件,有几个宏定义可用于设置或检测fd_set:
FD_ZERO(fd_set *fdset) // 将fd_set中的所有bit置0
FD_SET(int fd, fd_set *fdset) // 设置值为fd的描述符对应的事件为关注事件
FD_ISSET(int fd, fd_set *fdset) // 检测值为fd的描述符对应的事件是否就绪
使用select检测就绪事件需要注意一点:每次select返回之后,fd_set中的数据会失效,需要重新设置,超时时间也是如此。