在非阻塞下select函数的使用
函数原型
int select(nfds, readfds, writefds, exceptfds, timeout)
int nfds;
fd_set *readfds, *writefds, *exceptfds;
struct timeval *timeout;
ndfs:select 监视各文件中的最大文件号加一。
比如有两个文件描述符fd1,fd2 则
ndfs = fd1 > fd2 ? fd1+1 : fd2+1;
readfds:select 监视的可读文件句柄集合。
writefds: select 监视的可写文件句柄集合。
exceptfds:select 监视的异常文件句柄集合。
timeout:本次 select()的超时结束时间。
超时时间设置
第一,若将 NULL 以形参传入,即不传入时间结构,就是将 select 置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
第三,timeout 的值大于0,这就是等待的超时时间,即 select 在 timeout 时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回
select函数的返回值
负值:select 错误
正值:某些文件可读写或出错
0:等待超时,没有可读写或错误的文件
调用select()以后,如果返回正值,需判断是读/写/异常
使用FD_ISSET(int fd, fd_set *)判断
以阻塞写函数为例进行具体分析
static ssize_t write_nonblock(int fd, void *buf, size_t count)
{
size_t nc=0; int err=0;
/* simulate a 10 seconds timeout */
struct timeval to;
int nr_tries=10;
fd_set wfds, efds;//write/error fd
if (fd < 0 || !buf)
return -1;
while (count > 0) {
err = write(fd, buf, count);
if (err > 0) {
buf += err;
nc += err;
count -= err;
continue;
}
if (err < 0 && errno != EAGAIN)
/* Error occurs */
break;
if (--nr_tries == 0)
/* Timeout: * Didn't send out anything in the continuous 10 seconds
*/
break;
//在调用select()函数之前,必须清0,文件句柄集合
//清除写句柄集合
FD_ZERO(&wfds);
//清除错误句柄集合
FD_ZERO(&efds);
//初始化句柄集合
FD_SET(fd, &wfds);
FD_SET(fd, &efds);
//延迟1s
to.tv_sec = 1;
to.tv_usec = 0;
err = select(fd+1, NULL, &wfds, &efds, &to);
/
/*select会监视句柄集合在1s中是否有变化,然后返回*/
//若 err==0,则继续掩延时,直到10s超时
if (err > 0) {
//句柄有变化,判断是可读还是异常
if (FD_ISSET(fd, &wfds)) {
/ //
/* Can write data again
* We better give it a little sleep,
* for writing large blocks with less times of retry
*/
_SCHEDULE();
continue;
}
if (FD_ISSET(fd, &efds)) {
/ /
/* Error occurs */
err = -1;
break;
}
} }
else if (err < 0)
/ /
/* Error occurs */
break;
} }
if (!nc && err < 0)
return -1;
if (!nc)
/* EAGAIN */
return -1;
return nc;
}
在非阻塞下select函数的使用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.