zoukankan      html  css  js  c++  java
  • 各I/O模型 对应Web服务应用模型(select,poll,epoll,kevent,"/dev/poll")

    一、利用select多路复用I/O的Web服务应用模型 

    /* 可读、可写、异常三种文件描述符集的申明和初始化。*/ 
    fd_set readfds, writefds, exceptionfds; 
    FD_ZERO(&readfds); 
    FD_ZERO(&writefds); 
    FD_ZERO(&exceptionfds); 
    
    int max_fd; 
    
    /* socket配置和监听。*/ 
    sock = socket(...); 
    bind(sock, ...); 
    listen(sock, ...); 
    
    /* 对socket描述符上发生关心的事件进行注册。*/ 
    FD_SET(&readfds, sock); 
    max_fd = sock; 
    
    while(1) { 
    int i; 
    fd_set r,w,e; 
    
    /* 为了重复使用readfds 、writefds、exceptionfds,将它们拷贝到临时变量内。*/ 
    memcpy(&r, &readfds, sizeof(fd_set)); 
    memcpy(&w, &writefds, sizeof(fd_set)); 
    memcpy(&e, &exceptionfds, sizeof(fd_set)); 
    
    /* 利用临时变量调用select()阻塞等待,等待时间为永远等待直到发生事件。*/ 
    select(max_fd + 1, &r, &w, &e, NULL); 
    
    /* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/ 
    if(FD_ISSET(&r, sock)){ 
    new_sock = accept(sock, ...); 
    FD_SET(&readfds, new_sock); 
    FD_SET(&writefds, new_sock); 
    max_fd = MAX(max_fd, new_sock); 
    } 
    /* 对其它描述符发生的事件进行适当处理。描述符依次递增,最大值各系统有所不同(比如在作者系统上最大为1024),在linux可以用命令ulimit -a查看(用ulimit命令也对该值进行修改)。在freebsd下,用sysctl -a | grep kern.maxfilesperproc来查询和修改。*/ 
    for(i= sock+1; i <max_fd+1; ++i) { 
    if(FD_ISSET(&r, i)) 
    doReadAction(i); 
    if(FD_ISSET(&w, i)) 
    doWriteAction(i); 
    } 
    } 

    二、利用poll多路复用I/O的Web服务应用模型 

    /* 新建并初始化文件描述符集。*/ 
    struct pollfd fds[MAX_NUM_FDS]; 
    int max_fd; 
    
    /* socket配置和监听。*/ 
    sock = socket(...); 
    bind(sock, ...); 
    listen(sock, ...); 
    
    /* 对socket描述符上发生关心的事件进行注册。*/ 
    fds[0].fd = sock; 
    fds[0].events = POLLIN; 
    max_fd = 1; 
    
    while(1) { 
    int i; 
    
    /*调用poll()阻塞等待,等待时间为永远等待直到发生事件。*/ 
    poll(fds, max_fd, -1); 
    
    /* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/ 
    if(fds[0].revents & POLLIN){ 
    new_sock = accept(sock, ...); 
    fds[max_fd].fd = new_sock; 
    fds[max_fd].events = POLLIN | POLLOUT; 
    ++ max_fd; 
    } 
    /* 对其它描述符发生的事件进行适当处理。*/ 
    for(i=1; i <max_fd+1; ++i) { 
    if(fds.revents & POLLIN) 
    doReadAction(i); 
    if(fds.revents & POLLOUT) 
    doWriteAction(i); 
    } 
    } 
    
    利用epoll多路复用I/O的Web服务应用模型 
    /* 新建并初始化文件描述符集。*/ 
    struct epoll_event ev; 
    struct epoll_event events[MAX_EVENTS]; 
    
    /* 创建epoll句柄。*/ 
    int epfd = epoll_create(MAX_EVENTS); 
    
    /* socket配置和监听。*/ 
    sock = socket(...); 
    bind(sock, ...); 
    listen(sock, ...); 
    
    /* 对socket描述符上发生关心的事件进行注册。*/ 
    ev.events = EPOLLIN; 
    ev.data.fd = sock; 
    epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev); 
    
    while(1) { 
    int i; 
    /*调用epoll_wait()阻塞等待,等待时间为永远等待直到发生事件。*/ 
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1); 
    for(i=0; i <n; ++i) { 
    /* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/ 
    if(events.data.fd == sock) { 
    if(events.events & POLLIN){ 
    new_sock = accept(sock, ...); 
    ev.events = EPOLLIN | POLLOUT; 
    ev.data.fd = new_sock; 
    epoll_ctl(epfd, EPOLL_CTL_ADD, new_sock, &ev); 
    } 
    }else{ 
    /* 对其它描述符发生的事件进行适当处理。*/ 
    if(events.events & POLLIN) 
    doReadAction(i); 
    if(events.events & POLLOUT) 
    doWriteAction(i); 
    } 
    } 
    } 

    三、利用kqueue多路复用I/O的Web服务应用模型

    /* 新建并初始化文件描述符集。*/ 
    struct kevent changelist[MAX_EVENTS]; 
    struct kevent eventlist[MAX_EVENTS]; 
    int count = 0; 
    
    /* 创建kqueue句柄。*/ 
    int kqfd = kqueue(); 
    
    /* socket配置和监听。*/ 
    sock = socket(...); 
    bind(sock, ...); 
    listen(sock, ...); 
    
    /* 对socket描述符上发生关心的事件进行注册。*/ 
    EV_SET(&changelist[0], sock, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, 
    0, 0, 0); 
    ++ count; 
    
    while(1) { 
    int i; 
    /*调用kevent()阻塞等待,等待时间为永远等待直到发生事件。*/ 
    int n = kevent(kqfd, changelist, count, eventlist, count, NULL); 
    for(i=0; i <n; ++i) { 
    /* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/ 
    if(eventlist.ident == sock) { 
    new_sock = accept(sock, ...); 
    EV_SET(&changelist[count], new_sock, EVFILT_READ, 
    EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); 
    ++ count; 
    }else{ 
    /* 对其它描述符发生的事件进行适当处理。*/ 
    doReadAction(i); 
    } 
    } 
    } 


    四、利用/dev/poll多路复用I/O的Web服务应用模型

    /* 新建并初始化文件描述符集。*/ 
    struct pollfd pfd; 
    struct pollfd pollfds[MAX_EVENTS]; 
    struct dvpoll dopoll; 
    int count = 0; 
    
    /* 打开/dev/poll设备,创建poll句柄。*/ 
    int dpfd = open("/dev/poll", O_RDWR); 
    
    /* socket配置和监听。*/ 
    sock = socket(...); 
    bind(sock, ...); 
    listen(sock, ...); 
    
    /* 对socket描述符上发生关心的事件进行注册。*/ 
    pfd.fd = sock; 
    pfd.events = EPOLLIN; 
    pfd.revents = 0; 
    write(dpfd, pfd, sizeof(pfd)); 
    ++ count; 
    
    while(1) { 
    int i; 
    /*调用ioctl()阻塞等待,等待时间为永远等待直到发生事件。*/ 
    dopoll.dp_timeout = -1; 
    dopoll.dp_nfds = count; 
    dopoll.dp_fds = &pollfds; 
    int n = ioctl(dpfd, DP_POLL, &dopoll); 
    for(i=0; i <n; ++i) { 
    /* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/ 
    if(pollfds.fd == sock) { 
    if(pollfds.revents & POLLIN){ 
    new_sock = accept(sock, ...); 
    pfd.fd = new_sock; 
    pfd.events = EPOLLIN | POLLOUT; 
    pfd.revents = 0; 
    write(dpfd, pfd, sizeof(pfd)); 
    ++ count; 
    } 
    }else{ 
    /* 对其它描述符发生的事件进行适当处理。*/ 
    if(pollfds.revents & POLLIN) 
    doReadAction(i); 
    if(pollfds.revents & POLLOUT) 
    doWriteAction(i); 
    } 
    } 
    } 


    五、利用rtsig多路复用I/O的Web服务应用模型

    /* 新建并初始化关注信号。*/ 
    sigset_t sigset; 
    siginfo_t siginfo; 
    
    sigemptyset(&sigset); 
    sigaddset(&sigset, SIGRTMIN + 1); 
    sigaddset(&sigset, SIGIO); 
    
    
    /* socket配置和监听。*/ 
    sock = socket(...); 
    bind(sock, ...); 
    listen(sock, ...); 
    
    /* 重新设置描述符可读写时发送的信号值。*/ 
    fcntl(sock, F_SETSIG, SIGRTMIN + 1); 
    
    /* 对socket描述符设置所有者。*/ 
    fcntl(sock, F_SETOWN, getpid()); 
    
    /* 启用描述符的信号驱动I/O模式。*/ 
    fcntl(sock, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR); 
    
    while(1) { 
    struct timespec ts; 
    ts.tv_sec = 1; 
    ts.tv_nsec = 0; 
    
    /*调用sigtimedwait()阻塞等待,等待时间1秒。*/ 
    sigtimedwait(&sigset, &siginfo, &ts); 
    
    /* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/ 
    if(siginfo.si_fd == sock) { 
    new_sock = accept(sock, ...); 
    fcntl(new_sock , F_SETSIG, SIGRTMIN + 1); 
    fcntl(new_sock , F_SETOWN, getpid()); 
    fcntl(new_sock , F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR); 
    }else { 
    /* 对其它描述符发生的事件进行适当处理。*/ 
    doReadAction(i); 
    } 
    }

      

  • 相关阅读:
    Atitit 华为基本法 attilax读后感
    Atitit 华为管理者内训书系 以奋斗者为本 华为公司人力资源管理纲要 attilax读后感
    Atitit 项目版本管理gitflow 与 Forking的对比与使用
    Atitit 管理的模式扁平化管理 金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理
    Atitit 乌合之众读后感attilax总结 与读后感结构规范总结
    深入理解 JavaScript 异步系列(4)—— Generator
    深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
    深入理解 JavaScript 异步系列(2)—— jquery的解决方案
    深入理解 JavaScript 异步系列(1)——基础
    使用 github + jekyll 搭建个人博客
  • 原文地址:https://www.cnblogs.com/feika/p/3616658.html
Copyright © 2011-2022 走看看