epoll回显服务器
来源:互联网 发布:手机淘宝详情添加视频 编辑:程序博客网 时间:2024/04/30 20:50
epoll算是LINUX上最高效的服务器开发机制了,相比于select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。
epoll的使用非常简单,只需要使用三个函数就行了:epoll_create,epoll_wait,epoll_ctl,以下是使用epoll来实现回显服务器的一个例子,注释详尽,欢迎大家阅读。
#include <stdio.h>#include <unistd.h>#include <sys/epoll.h>#include <sys/socket.h>#include <fcntl.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <arpa/inet.h>#define MAXLINE 1024#define SERV_PORT 8877//发生了致命错误,输出错误后立即退出void error_quit(const char *str) { perror(str);exit(1); } int main(void) { int listenfd, connfd, sockfd, epfd; int i, res, maxi, nfds; ssize_t n; char buf[MAXLINE]; socklen_t clilen; struct sockaddr_in cliaddr; struct sockaddr_in servaddr; //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件 struct epoll_event ev, events[256]; //创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大 epfd = epoll_create(256); if( -1 == epfd )error_quit("epoll_create error");//创建用于TCP协议的套接字 listenfd = socket(AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); //把socket和socket地址结构联系起来 res = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); if( -1 == res )error_quit("bind error");//开始监听LISTENQ端口 res = listen(listenfd, INADDR_ANY); if( -1 == res )error_quit("listen error");//设置与要处理的事件相关的文件描述符和事件 ev.data.fd = listenfd; /*events可以是以下几个宏的集合:EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);EPOLLOUT:表示对应的文件描述符可以写;EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);EPOLLERR:表示对应的文件描述符发生错误;EPOLLHUP:表示对应的文件描述符被挂断;EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里*/ev.events = EPOLLIN|EPOLLET; //注册epoll事件 epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd,&ev); maxi = 0; while(1) { //等待epoll事件的发生 //返回需要处理的事件数目nfds,如返回0表示已超时。 nfds = epoll_wait(epfd, events, 20, 500); //处理所发生的所有事件 for(i=0; i < nfds; ++i) { //如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。 if(events[i].data.fd == listenfd) { connfd = accept(listenfd,(struct sockaddr *)&cliaddr, &clilen); if( -1 == connfd )error_quit("accept error"); //注册用于读操作的文件描述符和事件 ev.data.fd = connfd; ev.events = EPOLLIN|EPOLLET; res = epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev); if( -1 == res )error_quit("epoll_ctl error");} //如果是已经连接的用户,并且收到数据,那么进行读入。 else if(events[i].events & EPOLLIN) { sockfd = events[i].data.fd; if ( sockfd < 0 ) continue; n = read(sockfd, buf, MAXLINE); if ( n < 0) { // Connection Reset:你连接的那一端已经断开了, //而你却还试着在对方已断开的socketfd上读写数据! if (errno == ECONNRESET) { close(sockfd); events[i].data.fd = -1; } else error_quit("read error"); } //如果读入的数据为空 else if ( n == 0 ) { close(sockfd); events[i].data.fd = -1; } else { //注册用于写操作的文件描述符和事件 ev.data.fd = sockfd; ev.events = EPOLLOUT|EPOLLET; res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); if( -1 == res )error_quit("epoll_ctl error");} } //如果有数据发送 else if(events[i].events & EPOLLOUT) { sockfd = events[i].data.fd; write(sockfd, buf, n); //注册用于读操作的文件描述符和事件 ev.data.fd = sockfd; ev.events = EPOLLIN|EPOLLET; res = epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev); if( -1 == res )error_quit("epoll_ctl error");} } } return 0; }
qch@qch ~/program/tcode $ gcc server.c -o serverqch@qch ~/program/tcode $ ./server &[1] 4773qch@qch ~/program/tcode $ telnet localhost 8877.........abcde abcde.........
- epoll回显服务器
- epoll多进程回显服务器示例
- epoll学习和回显服务器实现(C语言版)
- epoll学习和回显服务器实现(C语言版)
- epoll服务器
- epoll服务器
- epoll服务器
- epoll服务器
- Epoll服务器
- epoll服务器
- epoll服务器
- C++实现epoll回射服务器
- linux服务器编程--EPOLL
- epoll服务器示例
- 并发服务器之epoll
- epoll服务器编程-demo
- epoll服务器开发详解
- Epoll服务器架构
- ORANGE'S之三-保护模式(3)
- 1.S3C2440A存储器映射
- 快速开发平台的原理和实现(三)
- Hibernate多对一 的处理
- tty open call stack
- epoll回显服务器
- linux系统中的DNS服务器介绍及配置实例详解
- 面向对象的设计原则
- Linux系统中main函数的执行过程
- shell中的点命令与source命令
- 《代码大全》 子程序质量检查表
- JAVA Properties类解析读取属性文件
- WIN7运行命令大全
- BOOL,float,指针变量与零值比较的if语句