在非阻塞下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函數的使用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.