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事件库使用笔记的主要内容,如果未能解决你的问题,请参考以下文章

libevent学习笔记(参考libevent深度剖析)

Libevent 学习笔记 ——Libevent 2.0安装与简单演示样例

浅析libevent

基于事件驱动的高性能开源网络库libevent介绍及安装

libevent学习过程

libevent和基于libevent的网络编程