select监听的文件描述最大为FD_SETSIZE,一般为1024
客户端在1024以下使用select是合适的,因为客户端一旦过多就会采用轮询模型,会大大降低响应效率。
使用man select 查看帮助文档
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
nfds: 监控最大文件描述符加一,此参数会通知内核检测前多少个文件描述符的状态
readfds: 监控读数据文件描述符的集合,传入传出参数
writefds: 监控写数据文件描述符的集合,传入传出参数
exceptfds: 监控异常数据文件描述符的集合,传入传出参数
timeout:定时堵塞,分三种情况
1.NULL:堵塞
2.timeval 时间内堵塞,一旦超过时间就返回
3.0,不堵塞立即返回
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
FD_CLR(),把文件描述符在set中清空
FD_ISSET,测试fd是否集合置1
FD_SET,把fd在集合置1
FD_ZERO ,把集合所有位置置0
此select主要用于在时间内的连接,例如select 函数与accept结合使用
int ret=0;
fd_set read_fdset;
struct timeval timeout;
//初始化集合
FD_ZERO(&read_fdset);
//fd加入到集合中
FD_SET(fd, &accept_fdset);
//设置时间间隔为三秒
timeout.tv_sec = 3;
timeout.tv_usec = 0;
do
{
//把fd设置读监听
ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout);
} while (ret < 0 && errno == EINTR);
if (ret == -1)
//连接错误
return -1;
else if (ret == 0)
{
//连接超时
return 0;
}
//如果三秒监控到有读时间,就会调用accept函数,并且不会因为没有设置accept非堵塞而堵塞
socklen_t addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in client;
ret = accept(fd, (struct sockaddr*)&client, &addrlen);
if (ret == -1)
{
ret = errno;
return ret;
}
return ret;