select函数允许进程指示内核等待多个事件中的任何一个发生,并且在有一个或多个事件发生或经历一段指定时间后才唤醒。
1.函数原型:
int select (int maxfd + 1,fd_set *readset,fd_set *writeset, fd_set *exceptset,const struct timeval * timeout);
参数:
maxfd + 1: 表示待测试的描述符个数。加1的作用是指,描述符计数从0开始,则用加1表示个数。
readset,writeset,exceptset:
让内核测试读,写,异常条件的描述符。如果我们对某一个条件不感兴趣,则用NULL表示。
这三个参数是 值-结果 参数,函数返回时,结果将指示哪些描述符已就绪。在每次调用 select时,需要将所有描述符集内所关心的位均置1.
struct fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄。fd_set集合可以通过一些宏由人为来操作。
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表示可读写。
(1)执行FD_ZERO(&set); 则set用位表示是0000,0000。
(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
timeout:
struct timeval{
long tv_sec; // seconds
long tv_usec; // microseconds
}
存在三种情况:
NULL表示仅在有一个描述符准备好I/O时才返回,否则永远等待。
设置值,仅在有一个描述符准备好I/O时才返回,否则等待一段设定的时间。
0,表示检测描述符后立即返回,称为轮询。
返回值:
所有描述符集的已就绪的总位数。
2.模型表示
3.函数使用
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/time.h>
#include<unistd.h>
#include<string.h>
const int LEN = 1024;
int fds[2]; //只监测标准输入与输出这两个文件描述符
int main()
{
int std_in = 0;
int std_out = 1;
int fds_max = 1;
fd_set reads, writes;
struct timeval timeout;
fds[0] = std_in;
fds[1] = std_out;
while(1)
{
FD_ZERO(&reads);
FD_ZERO(&writes);
FD_SET(std_in, &reads); //标准输入关注的是读事件:reads这个集合中, 00000001
FD_SET(std_out, &writes); //标准输出关注的是写事件 :writes这个集合中,00000010
timeout.tv_sec = 5;
timeout.tv_usec = 0;
switch( select(fds_max + 1, &reads, &writes, NULL, &timeout))
{
case 0:
printf("select time out ......\n");
break;
case -1:
perror("select");
break;
default:
if(FD_ISSET(fds[0], &reads)) //可以从标准输入中读,判断,当std_in上发生事件,则reads为00000001,则满足FD_ISSET判断
{
char buf[LEN];
memset(buf, '\0', LEN);
//getns(buf);
scanf("%s",buf);
printf("echo: %s\n", buf); //读取后回显
if(strncmp(buf, "quit", 4) == 0) //退出
{
exit(0);
}
}
if(FD_ISSET(fds[1], &writes))//判断,当std_out上发生事件,则writes为00000010,则满足
{
char* buf = "write is ready.......\n";
printf("%s", buf);
sleep(5);//等待输入
}
break;
}
}
}
运行结果:
toney@sw2:~/study/network$ ./a.out
write is ready.......
123
echo: 123
write is ready.......
^C