您的位置:首页 > 其它

文章标题

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;


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: