1,select:正常使用
轮询的方式,从多个文件描述符中获取状态变化后的情况。
头文件:
#include <sys/time.h> //for struct timeval
#include <unistd.h> //for select
函数原型:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
nfds: 要检测的文件描述符的范围,为文件最大描述符+1
readfds: 包含所有可能因状态变成可读而触发select函数返回的文件描述符
writefds: 包含所有可能因状态变成可写而触发select函数返回的文件描述符
exceptfds: 包含所有可能因状态发生异常而触发select函数返回的文件描述符
timeout:struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
返回值:
当超时或其中一个/多个文件描述符发生变化时,此函数将返回,返回值:
-1: 函数执行出错
0: 超时,并将时间结构体清空为0
0: 状态变化的文件描述符的个数
事例:
fd_set rdfds;
struct timeval tv;
int rtn = 0;
FD_ZERO(&rdfds); //清空fd_set
FD_SET(socket, &rdfds); //将要检测的socket描述符加入到fd_set集合中
tv.tv_sec = 2;
tv.tv_usec = 1000; //设置超时时间为2s+1ms
rtn = select(socket+1, &rdfds, NULL, NULL, &tv);
if(rtn < 0)
perror("select");
else if(0 == rtn)
printf("timeout\n");
else
{
printf("rtn = %d\n", rtn); //查看有多少个文件描述符发生了变化
if(FD_ISSET(socket, &rdfds)) //判断下这个socket是否状态真的变成了可读
{
recv(...);
}
}
2,实现精准定时器
秒级定时器:
void sec_sleep(unsigned sec) {
int err;
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = 0;
do {
err = select(0, NULL, NULL, NULL, &tv);
} while (err < 0 && errno == EINTR);
}
毫秒级定时器:
void msec_sleep(unsigned long msec) {
int err;
struct timeval tv;
tv.tv_sec = msec / 1000;
tv.tv_usec = (msec % 1000) * 1000;
do {
err = select(0, NULL, NULL, NULL, &tv);
} while (err < 0 && errno == EINTR);
}
微妙级定时器:
void usec_sleep(unsigned long usec) {
int err;
struct timeval tv;
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
do {
err = select(0, NULL, NULL, NULL, &tv);
} while (err < 0 && errno == ENTR);
}