select函数
场景:
终端即接收来自标准输入的信息(fd = 0)并作出,也接受listen套接字(fd = 3)的信息并创建对应的已连接描述符
作用:
监听多个文件描述符
相关函数定义:
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
struct timeval{
long tv_sec;//秒
long tv_usec;//微秒
};//已经在头文件定义好了的,直接用就行
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
/**
返回值有两:int和readfds(fd_set的指针)
int:准备好读的文件描述符个数,出错返回-1
readfds:准备好读的文件描述符集合
*/
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
参数说明:
nfds:
表示集合中所有文件描述符的范围,即所有文件描述符的最大值+1。
readfds:
待读文件描述符集合
怎么理解这个集合?传入一个fd_set,只有在fd位置为1的文件描述符才会被监听有无写入
比如fd = 0,flag = 1(stdin);
fd = 1,flag = 0;
fd = 2,flag = 0;
fd = 3,flag = 1(监听套接字描述符);
select只会监听fd = 0和fd = 3的文件是否准备好可以读了,只要有一个准备好了,select就会停止阻塞,返回,进程继续执行
操作集合fd_set的函数:
void FD_CLR(int fd, fd_set *set);//清除某一个被监视的文件描述符。(fd = fd的位置设为0)
int FD_ISSET(int fd, fd_set *set);//测试一个文件描述符是否是集合中的一员(fd = fd的位置是否为1)
void FD_SET(int fd, fd_set *set);//添加一个文件描述符,将set中的某一位设置成1;(fd = fd的位置设为1)
void FD_ZERO(fd_set *set);//清空集合中的文件描述符,将每一位都设置为0;(所有位置设为0)
writefds:NULL
exceptfds:NULL
timeout:
一个struct timeval指针,设置select的最大阻塞时长,如果为null,则会一直阻塞
返回值说明:
返回值有两:int和readfds(fd_set的指针)
int:准备好读的文件描述符个数,出错返回-1
readfds:准备好读的文件描述符集合
实例:
i/o多路复用服务器:
p686页代码、p688页代码
家庭作业12.32:
//-------------------------------main.cpp---------------------------
#include<stdio.h>
#include<iostream>
#define MAXLINE 1000
using namespace std;
char* tfgets_select(char * s,int size,FILE* stream);
int main(){
char buf[MAXLINE];
if (tfgets_select(buf, MAXLINE, stdin) == NULL)
printf("BOOM!\n");
else
printf("%s", buf);
return 0;
}
//------------------------------tfget.cpp-------------------------
#include<stdio.h>
#include<sys/select.h>
using namespace std;
//char* tfgets_proc(char * s,int size,FILE* stream){
//}
char* tfgets_select(char * s,int size,FILE* stream){
fd_set read_set,ready_set;
struct timeval t;
//初始化读集合
FD_ZERO(&read_set);
FD_SET(0,&read_set);
//初始化最大阻塞时间
t.tv_sec = 5;
t.tv_usec = 0;
//用ready_set复制read_set作为参数,因为ready_set还会作为返回值
ready_set = read_set;
select(0+1,&ready_set,NULL,NULL,&t);
if(FD_ISSET(0,&ready_set)){
return fgets(s, size, stream);
}
else{
return NULL;
}
}
//---------------------------makefile----------------------------
prog:main.o tfgets.o
g++ -o prog main.o tfgets.o
main.o:main.cpp
g++ -c main.cpp
tfgets.o:tfgets.cpp
g++ -c tfgets.cpp
clean:
rm -rf prog
rm -rf *.o