epoll_wait范围之后应该是一个循环 , 遍历所有的事件:
while(true){ nfds = epoll_wait(epfd,events,20,500); for(n=0;n<nfds;++n) { if(events[n].data.fd==listener) { //如果是主socket的事件的话 , 则表示 //有新连接进入了 , 进行新连接的处理 。client=accept(listener,(structsockaddr*)&local,&addrlen); if(client<0) //在此最好将client设置为非阻塞 { perror("accept"); continue; } setnonblocking(client);//将新连接置于非阻塞模式 ev.events=EPOLLIN|EPOLLET; //并且将新连接也加入EPOLL的监听队列 。注意: 并没有设置对写socket的监听 ev.data.fd=client; if(epoll_ctl(kdpfd,EPOLL_CTL_ADD,client,&ev)<0) { //设置好event之后 , 将这个新的event通过epoll_ctl加入到epoll的监听队列里面 , 这里用EPOLL_CTL_ADD来加一个新的epoll事件 , 通过EPOLL_CTL_DEL来减少一个 ,epoll事件 , 通过EPOLL_CTL_MOD来改变一个事件的监听方式 。 fprintf(stderr,"epollsetinsertionerror:fd=%d0,client); return-1; } } elseif(event[n].events&EPOLLIN) { //如果是已经连接的用户 , 并且收到数据 , 那么进行读入 int sockfd_r; if((sockfd_r=event[n].data.fd)<0) continue; read(sockfd_r,buffer,MAXSIZE); //修改该sockfd_r上要处理的事件为EPOLLOUT , 这样可以监听写缓存是否可写 , 直到可写时才写入数据 ev.data.fd=sockfd_r; ev.events=EPOLLOUT|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd_r,&ev) );//修改标识符 , 等待下一个循环时发送数据 , 异步处理的精髓 } elseif(event[n].events&EPOLLOUT) //如果有数据发送 { intsockfd_w=events[n].data.fd; write(sockfd_w,buffer,sizeof(buffer)); //修改sockfd_w上要处理的事件为EPOLLIN ev.data.fd=sockfd_w; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd_w,&ev) //修改标识符 , 等待下一个循环时接收数据 } do_use_fd(events[n].data.fd); } }epoll实例:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <sys/socket.h>#include <netdb.h>#include <fcntl.h>#include <sys/epoll.h>#include <string.h>#define MAXEVENTS 64//函数://功能:创建和绑定一个TCP socket//参数:端口//返回值:创建的socketstatic int create_and_bind (char *port){ struct addrinfo hints; struct addrinfo *result, *rp; int s, sfd; memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */ hints.ai_flags = AI_PASSIVE; /* All interfaces */ s = getaddrinfo (NULL, port, &hints, &result);//getaddrinfo解决了把主机名和服务名转换成套接口地址结构的问题 。 if (s != 0) { fprintf (stderr, "getaddrinfo: %sn", gai_strerror (s)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; s = bind (sfd, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } close (sfd); } if (rp == NULL) { fprintf (stderr, "Could not bindn"); return -1; } freeaddrinfo (result); return sfd;}//函数//功能:设置socket为非阻塞的static intmake_socket_non_blocking (int sfd){ int flags, s; //得到文件状态标志 flags = fcntl (sfd, F_GETFL, 0); if (flags == -1) { perror ("fcntl"); return -1; } //设置文件状态标志 flags |= O_NONBLOCK; s = fcntl (sfd, F_SETFL, flags); if (s == -1) { perror ("fcntl"); return -1; } return 0;}//端口由参数argv[1]指定int main (int argc, char *argv[]){ int sfd, s; int efd; struct epoll_event event; struct epoll_event *events; if (argc != 2) { fprintf (stderr, "Usage: %s [port]n", argv[0]); exit (EXIT_FAILURE); } sfd = create_and_bind (argv[1]); if (sfd == -1) abort (); s = make_socket_non_blocking (sfd); if (s == -1) abort (); s = listen (sfd, SOMAXCONN); if (s == -1) { perror ("listen"); abort (); } //除了参数size被忽略外,此函数和epoll_create完全相同 efd = epoll_create1 (0); if (efd == -1) { perror ("epoll_create"); abort (); } event.data.fd = sfd; event.events = EPOLLIN | EPOLLET;//读入,边缘触发方式 s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } /* Buffer where events are returned */ events = calloc (MAXEVENTS, sizeof event); /* The event loop */ while (1) { int n, i; n = epoll_wait (efd, events, MAXEVENTS, -1); for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* An error has occured on this fd, or the socket is not ready for reading (why were we notified then?) */ fprintf (stderr, "epoll errorn"); close (events[i].data.fd); continue; } else if (sfd == events[i].data.fd) { /* We have a notification on the listening socket, which means one or more incoming connections. */ while (1) { struct sockaddr in_addr; socklen_t in_len; int infd; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr; infd = accept (sfd, &in_addr, &in_len); if (infd == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { /* We have processed all incoming connections. */ break; } else { perror ("accept"); break; } } //将地址转化为主机名或者服务名 s = getnameinfo (&in_addr, in_len, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV);//flag参数:以数字名返回 //主机地址和服务地址 if (s == 0) { printf("Accepted connection on descriptor %d " "(host=%s, port=%s)n", infd, hbuf, sbuf); } /* Make the incoming socket non-blocking and add it to the list of fds to monitor. */ s = make_socket_non_blocking (infd); if (s == -1) abort (); event.data.fd = infd; event.events = EPOLLIN | EPOLLET; s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event); if (s == -1) { perror ("epoll_ctl"); abort (); } } continue; } else { /* We have data on the fd waiting to be read. Read and display it. We must read whatever data is available completely, as we are running in edge-triggered mode and won't get a notification again for the same data. */ int done = 0; while (1) { ssize_t count; char buf[512];count = read (events[i].data.fd, buf, sizeof(buf)); if (count == -1) { /* If errno == EAGAIN, that means we have read all data. So go back to the main loop. */ if (errno != EAGAIN) { perror ("read"); done = 1; } break; } else if (count == 0) { /* End of file. The remote has closed the connection. */ done = 1; break; } /* Write the buffer to standard output */ s = write (1, buf, count); if (s == -1) { perror ("write"); abort (); } } if (done) { printf ("Closed connection on descriptor %dn", events[i].data.fd); /* Closing the descriptor will make epoll remove it from the set of descriptors which are monitored. */ close (events[i].data.fd); } } } } free (events); close (sfd); return EXIT_SUCCESS;}
推荐阅读
- linux下高并发服务器实现
- 四个使用率最高的网络命令,你get了吗?
- 为什么网吧电脑配置不高,玩起来却从来不卡?
- 基于Linux系统的高可用中小型网站集群架构说明
- 直通车怎么提高质量得分 怎么提高直通车的质量分
- 春季提高宝宝免疫力很重要 可以多吃这些食物
- 春季长高正是好时节 宝宝春季增高妙招有哪些
- 盘点十大性价比高的汽车之豪华汽车
- 怎么提高直通车的质量分 淘宝直通车质量分迅速上10怎么操作
- 高马尾|58岁柔情硬汉相亲54岁大姐,一见面手脚就不安分,红娘:你离远点
