先贴一段代码再说,Linux下使用g++ -g-o server server.c -levent
可以直接使用gdb调试,而且可以跟踪到libevent的库里。

1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <netdb.h> 8 9 #include <event.h> 10 using namespace std; 11 12 // 事件base 13 struct event_base* base; 14 15 // 读事件回调函数 16 void onRead(int iCliFd, short iEvent, void *arg) 17 { 18 int iLen; 19 char buf[1500]; 20 21 iLen = recv(iCliFd, buf, 1500, 0); 22 23 if (iLen <= 0) { 24 cout << "Client Close" << endl; 25 26 // 连接结束(=0)或连接错误(<0),将事件删除并释放内存空间 27 struct event *pEvRead = (struct event*)arg; 28 event_del(pEvRead); 29 delete pEvRead; 30 31 close(iCliFd); 32 return; 33 } 34 35 buf[iLen] = 0; 36 cout << "Client Info:" << buf << endl; 37 38 39 40 struct bufferevent* buf_ev; 41 buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL); 42 buf_ev->wm_read.high = 4096; 43 char MESSAGE[]="welcome to server.."; 44 bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE)); 45 } 46 47 // 连接请求事件回调函数 48 void onAccept(int iSvrFd, short iEvent, void *arg) 49 { 50 int iCliFd; 51 struct sockaddr_in sCliAddr; 52 53 socklen_t iSinSize = sizeof(sCliAddr); 54 iCliFd = accept(iSvrFd, (struct sockaddr*)&sCliAddr, &iSinSize); 55 56 // 连接注册为新事件 (EV_PERSIST为事件触发后不默认删除) 57 struct event *pEvRead = new event; 58 event_set(pEvRead, iCliFd, EV_READ|EV_PERSIST, onRead, pEvRead); 59 event_base_set(base, pEvRead); 60 event_add(pEvRead, NULL); 61 62 63 struct bufferevent* buf_ev; 64 buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL); 65 buf_ev->wm_read.high = 4096; 66 char MESSAGE[]="welcome to server.."; 67 bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE)); 68 69 cout<<"a client connect:"<<iCliFd<<endl; 70 } 71 72 int main() 73 { 74 75 int iSvrFd; 76 struct sockaddr_in sSvrAddr; 77 78 memset(&sSvrAddr, 0, sizeof(sSvrAddr)); 79 sSvrAddr.sin_family = AF_INET; 80 sSvrAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 81 sSvrAddr.sin_port = htons(8888); 82 83 // 创建tcpSocket(iSvrFd),监听本机8888端口 84 iSvrFd = socket(AF_INET, SOCK_STREAM, 0); 85 bind(iSvrFd, (struct sockaddr*)&sSvrAddr, sizeof(sSvrAddr)); 86 listen(iSvrFd, 10); 87 88 // 初始化base 89 base = (struct event_base*)event_init(); 90 91 struct event evListen; 92 // 设置事件 93 event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, onAccept, NULL); 94 // 设置为base事件 95 event_base_set(base, &evListen); 96 // 添加事件 97 event_add(&evListen, NULL); 98 99 // 事件循环 100 event_base_dispatch(base); 101 102 return 0; 103 }
下面列出epoll服务端源码

1 #include <iostream> 2 #include <sys/socket.h> 3 #include <sys/epoll.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 #include <fcntl.h> 7 #include <unistd.h> 8 #include <stdio.h> 9 #include <errno.h> 10 11 using namespace std; 12 13 #define MAXLINE 5 14 #define OPEN_MAX 100 15 #define LISTENQ 20 16 #define SERV_PORT 5000 17 #define INFTIM 1000 18 19 void setnonblocking(int sock) 20 { 21 int opts; 22 opts=fcntl(sock,F_GETFL); 23 if(opts<0) 24 { 25 perror("fcntl(sock,GETFL)"); 26 exit(1); 27 } 28 opts = opts|O_NONBLOCK; 29 if(fcntl(sock,F_SETFL,opts)<0) 30 { 31 perror("fcntl(sock,SETFL,opts)"); 32 exit(1); 33 } 34 } 35 36 int main(int argc, char* argv[]) 37 { 38 int i, maxi, listenfd, connfd, sockfd,epfd,nfds, portnumber; 39 ssize_t n; 40 char line[MAXLINE]; 41 socklen_t clilen; 42 43 44 if ( 2 == argc ) 45 { 46 if( (portnumber = atoi(argv[1])) < 0 ) 47 { 48 fprintf(stderr,"Usage:%s portnumber/a/n",argv[0]); 49 return 1; 50 } 51 } 52 else 53 { 54 fprintf(stderr,"Usage:%s portnumber/a/n",argv[0]); 55 return 1; 56 } 57 58 59 60 //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件 61 62 struct epoll_event ev,events[20]; 63 //生成用于处理accept的epoll专用的文件描述符 64 65 epfd=epoll_create(256); 66 struct sockaddr_in clientaddr; 67 struct sockaddr_in serveraddr; 68 listenfd = socket(AF_INET, SOCK_STREAM, 0); 69 //把socket设置为非阻塞方式 70 71 //setnonblocking(listenfd); 72 73 //设置与要处理的事件相关的文件描述符 74 75 ev.data.fd=listenfd; 76 //设置要处理的事件类型 77 78 ev.events=EPOLLIN|EPOLLET; 79 //ev.events=EPOLLIN; 80 81 //注册epoll事件 82 83 epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); 84 bzero(&serveraddr, sizeof(serveraddr)); 85 serveraddr.sin_family = AF_INET; 86 char *local_addr="127.0.0.1"; 87 inet_aton(local_addr,&(serveraddr.sin_addr));//htons(portnumber); 88 89 serveraddr.sin_port=htons(portnumber); 90 bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr)); 91 listen(listenfd, LISTENQ); 92 maxi = 0; 93 for ( ; ; ) { 94 //等待epoll事件的发生 95 96 nfds=epoll_wait(epfd,events,20,500); 97 //处理所发生的所有事件 98 99 for(i=0;i<nfds;++i) 100 { 101 if(events[i].data.fd==listenfd)//如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。 102 103 { 104 connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); 105 if(connfd<0){ 106 perror("connfd<0"); 107 exit(1); 108 } 109 //setnonblocking(connfd); 110 111 char *str = inet_ntoa(clientaddr.sin_addr); 112 cout << "accapt a connection from " << str << endl; 113 //设置用于读操作的文件描述符 114 115 ev.data.fd=connfd; 116 //设置用于注测的读操作事件 117 118 ev.events=EPOLLIN|EPOLLET; 119 //ev.events=EPOLLIN; 120 121 //注册ev 122 123 epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); 124 } 125 else if(events[i].events&EPOLLIN)//如果是已经连接的用户,并且收到数据,那么进行读入。 126 127 { 128 cout << "EPOLLIN" << endl; 129 if ( (sockfd = events[i].data.fd) < 0) 130 continue; 131 if ( (n = read(sockfd, line, MAXLINE)) < 0) { 132 if (errno == ECONNRESET) { 133 close(sockfd); 134 events[i].data.fd = -1; 135 } else 136 std::cout<<"readline error"<<std::endl; 137 } else if (n == 0) { 138 close(sockfd); 139 events[i].data.fd = -1; 140 } 141 line[n] = '/0'; 142 cout << "read " << line << endl; 143 //设置用于写操作的文件描述符 144 145 ev.data.fd=sockfd; 146 //设置用于注测的写操作事件 147 148 ev.events=EPOLLOUT|EPOLLET; 149 //修改sockfd上要处理的事件为EPOLLOUT 150 151 //epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); 152 153 } 154 else if(events[i].events&EPOLLOUT) // 如果有数据发送 155 156 { 157 sockfd = events[i].data.fd; 158 write(sockfd, line, n); 159 //设置用于读操作的文件描述符 160 161 ev.data.fd=sockfd; 162 //设置用于注测的读操作事件 163 164 ev.events=EPOLLIN|EPOLLET; 165 //修改sockfd上要处理的事件为EPOLIN 166 167 epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); 168 } 169 } 170 } 171 return 0; 172 }