网络编程学习:io模型之io多路复用

多路复用的概念:

简而言之,就是将准备要用的文件描述符添加到一张表里,然后让select等待表里的任一描述符准备就绪(就是可以执行了),然后执行那个已经准备就绪的文件描述符,然后把其他的没有准备好的文件描述符全都删除;

援引知乎上的一个解释:

这些名词比较绕口,理解涵义就好。一个epoll场景:一个酒吧服务员(一个线程),前面趴了一群醉汉,突然一个吼一声“倒酒”(事件),你小跑过去给他倒一杯,然后随他去吧,突然又一个要倒酒,你又过去倒上,就这样一个服务员服务好多人,有时没人喝酒,服务员处于空闲状态,可以干点别的玩玩手机。至于epoll与select,poll的区别在于后两者的场景中醉汉不说话,你要挨个问要不要酒,没时间玩手机了。io多路复用大概就是指这几个醉汉共用一个服务员。
作者:匿名用户链接:https://www.zhihu.com/question/32163005/answer/55687802
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

io多路复用函数

int select(int maxfdpl, fd_set *readset, fd_set *writeset, fd_set exceptset, const struct timeval *timeout);
功能:允许一个进程去操作多个文件描述符,阻塞等待一个或多个文件描述符就绪,当有一个或者多个文件描述符准备就绪,则函数立即返回;

参数:
maxfdpl:指定待测试的描述符个数,它的值是描述符集合中最大值加1(因为描述符是从0开始的,例如:集合里有{0,1,2,3,4},此时描述符的个数为5(即最大值4加1));
readset:读文件描述符集合;
writeset:写文件描述法集合;
exceptset:异常条件的描述符集合;
timeout:它告知内核等待所指定的描述符中的任何一个多长时间,即用作超时检测;

返回值:
成功:
如果timeout == NULL,则返回准备就绪的文件描述的个数;
如果timeout != NULL,超时后返回0;
失败:
返回-1;

多路复用实例(让标准输入和accept同时可以被操作)

服务器端
#include "select.h"

int main(int argc, const char *argv[])
{   
    int listenfd, connfd;
    struct sockaddr_in servaddr, cliaddr;
    socklen_t addrlen = sizeof(struct sockaddr_in);
    char buf[N];

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        errlog("socket error");
    }

    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(atoi(argv[2]));

    if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
    {
        errlog("inet_pton error");
    }

    if(bind(listenfd, (struct sockaddr *)&servaddr, addrlen) < 0)
    {
        errlog("bind error");
    }

    if(listen(listenfd, LISTENQ) < 0)
    {
        errlog("listen error");
    }

    int maxfd;
    fd_set readfds, middlefds;

    //清空集合
    FD_ZERO(&readfds);

    maxfd = listenfd;

    while(1)
    {
        //将标准输入和接收客户端连接加入到集合中
        FD_SET(0, &readfds);
        FD_SET(listenfd, &readfds);

        //阻塞检测&readfds中哪个文件描述符准备好了,如果准备好了,就不再阻塞给下边的代码放行,同时清空那些没有准备好的文件描述符;
        if(select(maxfd + 1, &readfds, NULL, NULL, NULL) < 0)
        {
            errlog("select error");
        }

        //检测readfds集合中0号文件描述符准备好了没有,准备好了的话则返回1;
        if(FD_ISSET(0, &readfds))
        {
            fgets(buf, N, stdin);
            fputs(buf, stdout);
        }

        if(FD_ISSET(listenfd, &readfds))
        {
            if( (connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &addrlen)) < 0)
            {
                errlog("accept error");
            }

            printf("%s--%d is coming\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
        }
    }


    close(listenfd);
    close(connfd);

    return 0;
}

你可能感兴趣的:(net)