libev事件库使用笔记
源码下载地址:http://dist.schmorp.de/libev/
libev是一个高性能的事件循环库,比libevent库的性能要好。
安装:
1 tar -zxf libev-4.15.tar.gz 2 cd libev-4.15 3 ./configure 4 make 5 make install
设置环境变量:
设置一下环境变量(在文件/etc/profile中添加)。然后才可以运行。 1 export LIBDIR=/usr/local/lib 2 export LD_LIBRARY_PATH=/usr/local/lib 3 export LD_RUN_PATH=/usr/local/lib 添加完成后运行:source /etc/profile 使设置生效;
没有接触过libev的新手一般对概念也是比较蒙的,我也不多做介绍,教你如何快速上手
对比说明吧!
示例一:不使用libev
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <pthread.h> #include <errno.h> #define DAEMON_PORT 8888 #define MAX_LISTEN 1024 char get_manager_ip[16]; int adminserver(); void pthread_adminserver(int client_sd); int main(int argc, char** argv){ strcpy(get_manager_ip, argv[1]); adminserver(); } int adminserver() { int ret = 0; int i = 0; int max = 0; int nCurrentSocket = 0; FILE *fp; int res; int client_sd; int server_sd; int reuse_addr; pthread_t p_tcpserver; int client_addr_size ; struct sockaddr_in client_addr; struct sockaddr_in server_addr; char line[128]; char listen_ip[16]; char cmd_ip[128]; char *pt; char *edit; sprintf(cmd_ip,"ifconfig %s |grep 'addr:' >/get_manager_ip",get_manager_ip); system(cmd_ip); fp = fopen("/get_manager_ip","rb"); if (fp == NULL) { printf("Cann't open get_manger_ip file!\n"); exit(-1); } memset(line,0,128); fgets(line,128,fp); fclose(fp); pt=strstr(line, "addr:"); if (pt != NULL) { pt+=5; edit=strtok(pt," "); strcpy(listen_ip,edit); } server_sd=socket( AF_INET, SOCK_STREAM, 0 ); if (server_sd < 0) { printf("ERROR: Cann't create socket!!!\n"); exit(-1); } bzero(&server_addr, sizeof(struct sockaddr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr=inet_addr(listen_ip); server_addr.sin_port = htons(DAEMON_PORT); reuse_addr = 1; if (setsockopt (server_sd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) { printf("setsockopt error\n"); close(server_sd); return -1; } res = bind(server_sd, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (res < 0 ) { printf("Cann't bind!res = %d,erro:%d, reason:%s.\n",res, errno, strerror(errno)); close(server_sd); exit(-1); } if (listen( server_sd, MAX_LISTEN ) != 0 ) { printf("Cann't listen!\n"); close(server_sd); exit(-1); } while(1) { client_addr_size = sizeof(client_addr); client_sd = accept( server_sd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_size); if (pthread_create(&p_tcpserver, NULL, (void *)&pthread_adminserver, client_sd)!=0) { printf("Could not create thread check_work_time\n"); return ; } } close(server_sd); exit(1); } void pthread_adminserver(int client_sd) { int sockfd = 0; int rc; char buffer[4096]; while(1) { //线程处理某个客户端的连接 memset(buffer,0,4096); rc=read(client_sd,buffer,4096); if(strlen(buffer) == 0){ close(client_sd); //关闭线程处理的客户端连接 pthread_exit(0);//终止该线程 } printf("read date:\"%s\"\n",buffer); } close(client_sd); //关闭线程处理的客户端连接 pthread_exit(0);//终止该线程 }
说明:这是一个处理多并发的socket服务端,通过while接收多条连接,然后通过线程去处理每条连接,简单易懂,但是 使用两个while(1),是一件很浪费系统资源是事情;
示例二:通过示例一改动,添加libev
先对比两个示例先用起来吧,欢迎大神指导。
1 #include <ev.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <netinet/in.h> 6 #include <unistd.h> 7 8 #define PORT 8080 9 #define BUFFER_SIZE 1024 10 #define MAX_CONNECTIONS 10 11 12 struct ev_io *libevlist[MAX_CONNECTIONS] = {NULL}; 13 14 void socket_accept_callback(struct ev_loop *loop, struct ev_io *watcher, int revents); 15 void socket_read_callback(struct ev_loop *loop, struct ev_io *watcher, int revents); 16 /* 17 Server Client 18 19 20 socket socket 21 | | 22 v v 23 bind connect 24 | | 25 v v 26 listen write 27 | | 28 v v 29 accept read 30 | | 31 v v 32 read close 33 | 34 v 35 write 36 | 37 v 38 close 39 */ 40 41 int main() { 42 struct ev_loop *loop = ev_default_loop(0); 43 44 /* socket start */ 45 int sd; 46 struct sockaddr_in addr; 47 int addr_len = sizeof(addr); 48 49 struct ev_io *socket_watcher = (struct ev_io*)malloc(sizeof(struct ev_io)); 50 struct ev_timer *timeout_watcher = (struct ev_timer*)malloc(sizeof(struct ev_timer)); 51 52 // socket 53 sd = socket(PF_INET, SOCK_STREAM, 0); 54 if (sd < 0) { 55 printf("socket error\n"); 56 return -1; 57 } 58 bzero(&addr, sizeof(addr)); 59 addr.sin_family = AF_INET; 60 addr.sin_port = htons(PORT); 61 addr.sin_addr.s_addr = INADDR_ANY; 62 63 // bind 64 if (bind(sd, (struct sockaddr*) &addr, sizeof(addr)) != 0) { 65 printf("bind error\n"); 66 return -1; 67 } 68 // listen 69 if (listen(sd, SOMAXCONN) < 0) { 70 printf("listen error\n"); 71 return -1; 72 } 73 // set sd reuseful 74 int bReuseaddr = 1; 75 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (const char*) &bReuseaddr, sizeof(bReuseaddr)) != 0) { 76 printf("setsockopt error in reuseaddr[%d]\n", sd); 77 return -1; 78 } 79 /* socket end */ 80 81 ev_io_init(socket_watcher, socket_accept_callback, sd, EV_READ); 82 ev_io_start(loop, socket_watcher); 83 84 // while(1) { 85 ev_run(loop, 0); 86 // } 87 88 return 1; 89 } 90 91 void socket_accept_callback(struct ev_loop *loop, struct ev_io *watcher, int revents) { 92 printf("I am: %d\n", getpid()); 93 94 struct sockaddr_in client_addr; 95 socklen_t client_len = sizeof(client_addr); 96 int client_sd; 97 98 if (EV_ERROR & revents) { 99 printf("error event in accept\n"); 100 return; 101 } 102 103 // socket accept: get file description 104 client_sd = accept(watcher->fd, (struct sockaddr*) &client_addr, &client_len); 105 if (client_sd < 0) { 106 printf("accept error\n"); 107 return; 108 } 109 // too much connections 110 if (client_sd > MAX_CONNECTIONS) { 111 printf("fd too large[%d]\n", client_sd); 112 close(client_sd); 113 return; 114 } 115 116 if (libevlist[client_sd] != NULL) { 117 printf("client_sd not NULL fd is [%d]\n", client_sd); 118 return; 119 } 120 121 printf("client connected\n"); 122 // ev_io watcher for client 123 struct ev_io *client_watcher = (struct ev_io*) malloc(sizeof(struct ev_io)); 124 if (client_watcher == NULL) { 125 printf("malloc error in accept_cb\n"); 126 return; 127 } 128 // listen new client 129 ev_io_init(client_watcher, socket_read_callback, client_sd, EV_READ); 130 ev_io_start(loop, client_watcher); 131 132 libevlist[client_sd] = client_watcher; 133 } 134 135 void socket_read_callback(struct ev_loop *loop, struct ev_io *watcher, int revents) { 136 char buffer[BUFFER_SIZE]; 137 ssize_t read; 138 139 if (EV_ERROR & revents) { 140 printf("error event in read\n"); 141 return; 142 } 143 // socket recv 144 read = recv(watcher->fd, buffer, BUFFER_SIZE, 0); // read stream to buffer 145 if (read < 0) { 146 printf("read error\n"); 147 return; 148 } 149 150 if (read == 0) { 151 printf("client disconnected.\n"); 152 153 if (libevlist[watcher->fd] == NULL) { 154 printf("the fd already freed[%d]\n", watcher->fd); 155 } 156 else { 157 printf("fd:%d will be closed!\n",watcher->fd); 158 close(watcher->fd); 159 ev_io_stop(loop, libevlist[watcher->fd]); 160 free(libevlist[watcher->fd]); 161 libevlist[watcher->fd] = NULL; 162 } 163 return; 164 } 165 else { 166 printf("receive message[%d]says:%s\n",watcher->fd, buffer); 167 if(memcmp(buffer,"quit",strlen("quit")) == 0) 168 { 169 printf("recv quit cmd,fd:%d will be closed!\n",watcher->fd); 170 close(watcher->fd); 171 ev_io_stop(loop, libevlist[watcher->fd]); 172 free(libevlist[watcher->fd]); 173 libevlist[watcher->fd] = NULL; 174 return ; 175 } 176 } 177 178 // socket send to client 179 send(watcher->fd, buffer, read, 0); 180 bzero(buffer, sizeof(buffer)); 181 }