libev事件库使用笔记
Posted 你且浅笑相安
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
#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> #include <ev.h> //ev库头文件 #define DAEMON_PORT 8888 #define MAX_LISTEN 1024 ev_io read_watcher;//定义一个stdin的观测者 ev_io accept_watcher; ev_timer timeout_watcher; char get_manager_ip[16]; int adminserver(); void pthread_adminserver(int client_sd); static void read_cb(struct ev_loop *loop, ev_io *watcher, int events); static void accept_cb(struct ev_loop *loop, ev_io *watcher, int events) { int client_sd; int client_addr_size ; struct sockaddr_in client_addr; client_addr_size = sizeof(client_addr); client_sd = accept( watcher->fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_size); ev_io_init(&read_watcher,read_cb,client_sd,EV_READ); ev_io_start(loop,&read_watcher); } static void read_cb(struct ev_loop *loop, ev_io *watcher, int events) { char buffer[4096]; int rc; int client_addr_size ; memset(buffer,0,4096); rc=read(watcher->fd,buffer,4096); if(rc == 0){ close(watcher->fd); ev_io_stop(loop,&read_watcher); } printf("read date:\"%s\"\n",buffer); } int main(int argc, char** argv){ strcpy(get_manager_ip, argv[1]); adminserver(); } int adminserver() { struct ev_loop *loop = EV_DEFAULT; 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); } ev_io_init(&accept_watcher,accept_cb,server_sd,EV_READ);/**通过这里回调accept_cb函数,所使用观察者accept_watcher,传入参数问server_sd描述符,EV_READ标识这是一个读事件;**/ ev_io_start(loop,&accept_watcher);/*把一个accept观察者加入集合loop*/ ev_run(loop, 0);/*整个程序中只需要出现一次就好了,就是让观察者集合run起来,后面添加或者删除观察者只需要对loop进行操作;*/ }
先对比两个示例先用起来吧,欢迎大神指导。
以上是关于libev事件库使用笔记的主要内容,如果未能解决你的问题,请参考以下文章