各I/O模型 对应Web服务应用模型(select,poll,epoll,kevent,"/dev/poll")

来源:互联网 发布:python数据类型查看 编辑:程序博客网 时间:2024/05/17 02:41

各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); 
        } 
}

 

 

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

sigset_t sigset;
siginfo_t siginfo;

sigemptyset(&sigset);
sigaddset(&sigset, SIGRTMIN + 1);
sigaddset(&sigset, SIGIO);



sock = socket(...);
bind(sock, ...);
listen(sock, ...);


fcntl(sock, F_SETSIG, SIGRTMIN + 1);


fcntl(sock, F_SETOWN, getpid());


fcntl(sock, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);

while(1) {
struct timespec ts;
ts.tv_sec =   1;
ts.tv_nsec = 0;


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);
}

}

 

原创粉丝点击