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进行操作;*/
}

先对比两个示例先用起来吧,欢迎大神指导。

时间: 2024-10-06 20:58:34

libev事件库使用笔记的相关文章

移植libev事件库到Android中

因为libev库是使用C语言写的,所以在Android项目中使用此库的方法是把libev编译成.so文件,在Android中使用jni方式来调用libev的.so文件. 我们大家都知道android的ndk开发可以编译c,c++代码,不过需要自己写Android.mk文件.但是对于大多数开源项目来说,代码量很大,而且在编译前需要通过configure来配置编译选项,这种情况下,自己写Android.mk文件是很不现实的. 在这里,先参考如何使用android独立工具链快速移植开源项目中的方法实现

0806------Linux网络编程----------Echo 网络库 学习笔记

1.Echo网络库的编写 1.1 Echo网络库1.0 1.1.1 Echo网络库 1.0 框架分析 a)class InetAddress: 主要用来定义一个struct sockaddr_in 结构(用自定义端口号初始化),并提供获取这个结构体成员如IP.Port等的接口: b)class Socket : 主要用来把一个普通的 sockfd 变为 listenfd(这里用一个sockfd初始化对象),提供bind .listen.accept 等接口. c)class TcpConnect

DOM事件模型学习笔记

下面的内容属于阅读笔记,其中涉及大量内容来自于PPK的博客的内容,如果你要跟随我的脚步领略大家风采,那么就从Introduction to Events开始阅读吧. 现代的前端开发应该是会严格遵守 html 展示文档内容构成,css 渲染页面效果,javascript 提供交互 浏览器提供交互行为可以追溯到Netscape公司在其第二个版本中支持javascript语言,随后其与微软之间的浏览器大战,以及w3c标准制定的落后,导致至今一直被诟病的浏览器兼容问题,而这些不兼容中关于DOM事件模型的

Redis源码-事件库

网上看了很多Redis事件库的解读,自己也研究了好几遍,还是记录下来,虽然水平有限,但是进步总会是有的 网络事件库封装了Epoll的操作(当然是指Linux下的多路复用了),并且实现一个定时器,定时器也是服务端程序的基石,很多问题都需要靠定时器解决 (一)数据结构+算法构成一个完整的程序,要一窥Redis网络库,需要先从数据结构开始学习 1.整个事件循环是用一个全局的数据结构描述的,aeEventLoop /* State of an event based program */ typedef

javascript事件详解笔记

javascript事件详解笔记: 一.事件流 1.事件流: 描述的是页面中接受事件的顺序,有事件冒泡.事件捕获两种. 2.事件冒泡: 由最具体的元素接收,然后逐级向上传播到最不具体的元素的节点(文档). 3.事件捕获: 最不具体的节点先接收事件,而最具体的节点应该是最后接收事件. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>事件</title&

Yarn的服务库和事件库使用方法

事件类型定义: package org.apache.hadoop.event; public enum JobEventType { JOB_KILL, JOB_INIT, JOB_START } package org.apache.hadoop.event; public enum TaskEventType { T_KILL, T_SCHEDULE } 事件定义: package org.apache.hadoop.event; import org.apache.hadoop.yarn

js学习总结----移动端事件基础及常用的事件库

一.事件基础 PC:click.mouseover.mouseout.mouseenter.mouseleave.mousemove.mousedown.mouseup.mousewheel.keydown.keyup.load.scroll.blur.focus.change... 移动端:click(单击).load.scroll.blur.focus.change.input(代替keyup.keydown)...TOUCH事件模型(处理单手指操作).GESTURE事件模型(处理多手指操作

初探boost之timer库学习笔记

timer 用法 #include <boost/timer.hpp> #include <iostream> using namespace std; using namespace boost; int main() { timer t;//声明一个计时器对象,开始计时 cout<<"max:"<<t.elapsed_max()/3600<<"h"<<endl; //可度量的最大时间,以小时

初探boost之progress_display库学习笔记

progress_display 用途 progress_display可以在控制台上显示程序的执行进度,如果程序执行很耗费时间,那么它能提供一个友好的用户界 面,不至于让用户在等待中失去耐心,甚至怀疑程序的运行是否出了问题. 用法示例 #include <boost/progress.hpp> #include <iostream> #include <vector> using namespace std; using namespace boost; int ma