linux之select函式解析
select()的機制中提供一fd_set的資料結構,實際上是一long型別的陣列, 每一個數組元素都能與一開啟的檔案控制代碼(不管是Socket控制代碼,還是其他 檔案或命名管道或裝置控制代碼)建立聯絡,建立聯絡的工作由程式設計師完成, 當呼叫select()時,由核心根據IO狀態修改fd_set的內容,由此來通知執 行了select()的程序哪一Socket或檔案可讀,下面具體解釋:#include int select(nfds, readfds, writefds, exceptfds, timeout)
int nfds;fd_set *readfds, *writefds, *exceptfds;struct timeval *timeout;ndfs:select監視的檔案控制代碼數,視程序中開啟的檔案數而定,一般設為呢要監視各檔案 中的最大檔案號加一。
readfds:select監視的可讀檔案控制代碼集合。
writefds: select監視的可寫檔案控制代碼集合。
exceptfds:select監視的異常檔案控制代碼集合。
timeout:本次select()的超時結束時間。(見/usr/sys/select.h, 可精確至百萬分之一秒!)
當readfds或writefds中映象的檔案可讀或可寫或超時,本次select() 就結束返回。程式設計師利用一組系統提供的巨集在select()結束時便可判 斷哪一檔案可讀或可寫。對Socket程式設計特別有用的就是readfds. 幾隻相關的巨集解釋如下:FD_ZERO(fd_set *fdset):清空fdset與所有檔案控制代碼的聯絡。
FD_SET(int fd, fd_set *fdset):建立檔案控制代碼fd與fdset的聯絡。
FD_CLR(int fd, fd_set *fdset):清除檔案控制代碼fd與fdset的聯絡。
FD_ISSET(int fd, fdset *fdset):檢查fdset聯絡的檔案控制代碼fd是否可讀寫,>0表示可讀寫。
(關於fd_set及相關巨集的定義見/usr/include/sys/types.h)
這樣,你的socket只需在有東東讀的時候才讀入,大致如下:……
int sockfd;fd_set fdR;struct timeval timeout = ……;……
for(;;) { FD_ZERO(&fdR);FD_SET(sockfd, &fdR);switch (select(sockfd + 1, &fdR, NULL, &timeout)) { case -1:error handled by u;case 0:timeout hanled by u;default:if (FD_ISSET(sockfd)) { now u read or recv something;/* if sockfd is father and server socket, u
can now accept() */ }所以一個FD_ISSET(sockfd)就相當通知了sockfd可讀。
至於struct timeval在此的功能,請man select.不同的timeval設定 使使select()表現出超時結束、無超時阻塞和輪詢三種特性。由於timeval可精確至百萬分之一秒,所以Windows的SetTimer()根本不算 什麼。你可以用select()做一個超級時鐘。
[[email protected] select]$ cat select.c
/********************************************************************************** Copyright: (C) 2013 fulinux<[email protected]>
* All rights reserved.
*
* Filename: select.c
* Description: This file
*
* Version: 1.0.0(07/31/2013~)
* Author: fulinux <
* ChangeLog: 1, Release initial version on "07/31/2013 02:18:45 PM"
*
********************************************************************************/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int fds[2];
char buf[7];
int i,rc,maxfd;
fd_set inset1,inset2;
struct timeval tv;
if((fds[0] = open("hello1",O_RDWR|O_CREAT,0666)) < 0)
perror("open hello1");
if((fds[1] = open("hello2",O_RDWR|O_CREAT,0666)) < 0)
perror("open hello2");
if((rc = write(fds[0],"Hello!\n",7)))
printf("rc = %d\n",rc);
lseek(fds[0],0,SEEK_SET);
maxfd = fds[0] > fds[1] ? fds[0] : fds[1];
FD_ZERO(&inset1);
FD_SET(fds[0],&inset1);
FD_ZERO(&inset2);
FD_SET(fds[1],&inset2);
tv.tv_sec = 2;
tv.tv_usec = 0;
while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2))
{
if(select(maxfd+1,&inset1,&inset2,NULL,&tv) < 0)
perror("select");
else
{
if(FD_ISSET(fds[0],&inset1))
{
rc = read(fds[0],buf,7);
if(rc > 0)
{
buf[rc] = '\0';
printf("read: %s\n", buf);
}
else
perror("read");
}
}
if(FD_ISSET(fds[1],&inset2))
{
rc = write(fds[1],buf,7);
if(rc > 0)
{
buf[rc] = '\0';
printf("rc = %d, write: %s\n", rc,buf);
}
else
perror("write");
sleep(3);
}
}
exit(0);
}
[
[[email protected] select]$ ls
select.c
[[email protected] select]$ gcc select.c
[[email protected] select]$ ./a.out
rc = 7
read: Hello!
rc = 7, write: Hello!
read: Success
rc = 7, write: Hello!
read: Success
rc = 7, write: Hello!
read: Success
rc = 7, write: Hello!
read: Success
rc = 7, write: Hello!
^C
[[email protected] select]$ cat hello1
Hello!
[[email protected] select]$ cat hello2
Hello!
Hello!
Hello!
Hello!
Hello!
[[email protected] select]$