epoll
实现多路IO转接
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<ctype.h>
int main((int argc, char *argv[]){
int i,n,j;
int listenfd,connfd,efd,res,nready;
struct epoll_event tep,ep[OPEN_MAX];
char buf[BUFSIZ];
struct sockaddr_in clie_addr, serv_addr;
socklen_t clie_addr_len;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
int opt=1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port= htons(9527);
bind(listenfd, (struct sockaddr *) serv_addr, sizeof(serv_addr));
listen(listenfd,128);
efd = epoll_creat(OPEN_MAX);
if(efd==-1)
perr_exit("creat erro");
tep.event = EPOLLIN;
tep.data.fd = listenfd;
res=epoll_ctl(efd, EPOLL_CTL_ADD, listenfd, &tep);
if(res==-1)
perr_exit("epoll_ctl erro");
while(1){
nready = epoll_wait(efd, &ep, OPEN_MAX, -1);
if(nready == -1)
perr_exit("epoll_wait erro");
for(i=0;i<nready;++i){
if(!ep[i]&EPOLLIN)
continue;
if(ep[i].data.fd==listenfd){
clie_addr_len = sizeof(clie_addr);
connfd = accept(listenfd, (struct sockaddr *) clie_addr, clie_addr_len)
tep.event = EPOLLIN;
tep.data.fd= connfd;
res = epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &tep);
continue;
}
n = read(ep[i].data.fd, buf, sizeof(buf));
if(n==0){
res = epoll_ctl(efd, EPOLL_CTL_DEL, ep[i].data.fd, NULL);
close(ep[i].data.fd);
}
for(j=0;j<sizeof(buf);++j){
buf[j]=toupper(buf[j]);
}
write(ep[i], buf, n);
}
}
}
边沿触发和水平触发
就是模电里的知识,epoll默认是水平触发,也就是只要还有消息就会触发epoll_wait,边沿触发是有消息来才进行一次触发
如上图,管道内子程序写东西,一次写了10字节,“aaaa\nbbbb\n”,但是父进程读的时候一次读5个,也就是第一次读“aaaa\n”,这时管道内还有bbbb\n存在,如果是水平触发的话,读完第一次“aaaa\n”后,重新进行while循环的时候还是会触发epoll_wait,进行第二次读取,如果是边沿触发则不会在第二次while循环的时候读取了,直到子程序向管道内写入新的东西的时候才会读取bbbb\n