文章标题

来源:互联网 发布:mac系统被删除了 编辑:程序博客网 时间:2024/05/24 07:32
       浅谈三大常用的多路I/O转接模型之一:select 
  1. 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; // 初始化为-1maxi = 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;

}

0 0
原创粉丝点击