利用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;
int max_fd;
/* socket配置和监听。*/
sock = socket(...);
bind(sock, ...);
listen(sock, ...);
/* 对socket描述符上发生关心的事件进行注册。*/
fds.fd = sock;
fds.events = POLLIN;
max_fd = 1;
while(1) {
int i;
/*调用poll()阻塞等待,等待时间为永远等待直到发生事件。*/
poll(fds, max_fd, -1);
/* 测试是否有客户端发起连接请求,如果有则接受并把新建的描述符加入监控。*/
if(fds.revents & POLLIN){
new_sock = accept(sock, ...);
fds.fd = new_sock;
fds.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;
/* 创建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;
struct kevent eventlist;
int count = 0;
/* 创建kqueue句柄。*/
int kqfd = kqueue();
/* socket配置和监听。*/
sock = socket(...);
bind(sock, ...);
listen(sock, ...);
/* 对socket描述符上发生关心的事件进行注册。*/
EV_SET(&changelist, 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, 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;
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);
}
} .................
[ 本帖最后由 lenky0401 于 2009-3-3 10:21 编辑 ] 感谢楼主共享啊,学习一下 建议置顶. 原帖由 lenky0401 于 2009-2-17 09:31 发表 http://bbs.chinaunix.net/images/common/back.gif
我在看配置信息解析加载的时候 自己实际修改 编译 调试过
你是说 需要把如何修改 编译 调式 写个总结么?
那个和所有linux下程序编译是一样的:mrgreen:
在Ubuntu上面安装出现了很多问题,看来入门不容易:em16: :em16: 原帖由 aobai 于 2009-3-6 14:01 发表 http://bbs3.chinaunix.net/images/common/back.gif
在Ubuntu上面安装出现了很多问题,看来入门不容易:em16: :em16:
Ubuntu下
$ sudo apt-get install libpcre3-dev
$ sudo apt-get install zlib1g-dev
$ sudo apt-get install libglib2.0-dev
$ sudo apt-get install libaio-dev
$ sudo apt-get install libbz2-dev
$ ./configure
$ make
$ make install
具体可以参考
http://redmine.lighttpd.net/projects/lighttpd/wiki/TutorialInstallation