文章标题
2015-05-12 16:13
183 查看
浅谈三大常用的多路I/O转接模型之一:select
select
函数介绍:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
返回:若有描述符准备就绪返回已准备就绪的描述符个数, 若超时则为0,若出错则返回-1. fd_set可以理解为是一个集合类型,如{1,2,3}。 struct timeval { long tv_sec; // 秒 (struct timeval结构体可以理解 long tv_usec; // 微妙 成是一个定时器) };
参数详解:
nfds: select等待的最大描述符个数,其值为被等待的最大描述符的
值加1(maxfd + 1),因为描述符是从0开始的,当有一个描述符
时,其个数为1,以此类推,所以是(maxfd + 1)。
readfds: 该参数被设置,则是让内核测试读的描述符
writefds: 该变量如果被设置,则是让内核测试写的描述符
exceptfds: 该变量被设置,则是让内核测试异常的描述符
参数中的三个fd_set参数通常是一个数组,其中每个成员都是一个描述符,
一般与select配套使用的是四个宏:
void FD_ZERO(fd_set *set); // 把集合中的每一位清0;
void FD_SET(int fd, fd_set *set); // 把描述符fd加入集合set中;
void FD_CLR(int fd, fd_set *set); // 把描述符fd从集合set中删除;
void FD_ISSET(int fd, fd_set *set); // select返回时,检测时候是fd返回
select模型有个特定,每当select返回后,要想再进入阻塞状态,参数需要重新设置,所以,我们应该用一个数组来保存每次的描述符。为了便于理解我用一幅简单的图来表示select模型。
select模型常规使用方法:(为了精简代码,错误处理就不写了)
// 头文件 省略
define SA struct sockaddr_in
define MAXSIZE 1024 // 缓冲区最大值
int main(int argc, char* argv[]) {int sockfd, listenfd, connfd;
int nready, maxfd, maxi, i, n, client[MAXSIZE];
SA sv_addr;
socklen_t sv_len;
fd_set rset, allset;
char sendline[MAXSIZE];
listenfd = sockfd(AF_INET, SOCK_STREAM, 0); sv_len = sizeof(sv_addr); bzero(&sv_addr, sv_len); // 结构体清零 sv_addr.sin_family = AF_INET; sv_addr.sin_port = htons(atoi(argv[1])); sv_addr.sin_addr.s_addr = htonl(INADDR_ANY); bind(listenfd, (SA*)(&sv_addr),sv_len); listen(listenfd, 128); FD_ZERO(&allset); FD_SET(listenfd, &allset); for (i = 0; i < MAXSIZE; ++i) client[i] = -1; // 初始化为-1 maxi = 0; maxfd = listenfd; for ( ; ; ) { rset = allset; nready = select(maxfd + 1, &rset, NULL, NULL, NULL); if (FD_ISSET(listenfd, &rset)) { connfd = accept(listenfd, (SA*)(&sv_addr), &sv_len); for (i = 0; i < MAXSIZE; ++i) { if (client[i] < 0) { client[i] = connfd; break; } } if (i >= MAXSIZE) exit(EXIT_FAILURE); FD_SET(connfd, &allset); if (i > maxi) maxi = i; if (--nready == 0) continue; } for (i = 1; i <= maxi; ++i) { if ( (connfd = client[i]) < 0)) continue; n = read(connfd, sendline, MAXSIZE); write(connfd, sendline, n); if (--nready == 0) break; } } close(listenfd); return 0;
}