【转载】各I/O模型写了对应Web服务应用模型

【原创】各I/O模型写了对应Web服务应用模型

//by lenky
利用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);
       }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值