15.libevent使用 C++/Linux-2022-10-31

8.libevent

1.简介
  • 开源的库,提高开发效率
    • 封装了socket通信
    • 封装了IO多路转接
  • 精简,专注于网络,性能高
  • 事件驱动
2.libeveent库的安装
  • 官方网站:http://libevent.org
  • 安装
    • 解压:tar zxvf lib......
    • ./configure
      • --prefix == /user/xxx
      • 检测安装环境
      • 生成makefile
    • make
      • 编译源代码
      • 生成一些库
        • 动态静态
        • 可执行程序
      • sudo make install
        • 将数据拷贝到对应的目录
        • 如果目录不存在,创建该目录
        • 默认目录
          • /usr/local
            • /usr/local/include
            • /usr/local/bin
            • /usr/local/lib
  • 动态库找不到的问题
    • xxx.so放到环境变量中
      • LD_LIBRARY_PATH
        • export LD_LIBRARY_PATH = XXX
          • ~/.bashrc – 用户级别
          • /etc/protile–系统级别
        • 使用命令重新加载
          • .~/.bashrc
          • ./etc/profile
          • .等价于source
    • 修改/etc/ls.so.conf
      • 动态库路径添加到该文件中 - 绝对路径
      • sudo ldconfig -v
  • 库的使用
    • 编译程序指定 -levent
    • 常用头文件
      • #include <event2/event.h>
      • #include <event2/listener.h>
3.使用过程
  • 创建一个事件处理框架 – event_base
    • 使用libevent函数之前需要分配一个或者多个event_base结构题。每个event_base结构体都有一个事件集合,可以检测哪个事件是激活的。
    • 创建event_base
      • struct event_base* event_base_new(void);
      • 失败返回NULL
    • 释放event_base
      • event_base_free(struct event_base* base);
    • 循环监听base对应的事件,等待条件满足
      • event_base_dispatch();
    • 查看event_base封装的后端
      • const char **event_get_supported_methods(void);
        • char* str[];
      • const char *event_base_get_method(const struct event_base *base);
    • event_base fork()
      • 子进程创建成功之后,父进程可以继续使用event_base
      • 子进程中需要继续使用event_base需要重新进程初始化
        • int event_reinit(struct event_base* base);
  • 创建一个事件
    • event_new()
    • 设置未决事件
      • 构造事件之后,再将其添加到event_base之前实际上是不能对其做任何操作的。
      • int event_add(struct event *ev, const struct timeval *tv);
        • tv:
          • NULL:事件被触发,对应的回调被调用
          • tv={0,100},如果设置的时间在改时间段内检测的事件没被触发,时间到达之后,回调函数还是会被调用
        • 函数调用成功返回0,失败返回-1
    • 设置非未决
      • int event_del(struct event *ev);

一些宏

#define EV_TIMEOUT 0x01 //废弃
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10 //持续触发
#define EV_ET 0x20 //边沿模式
  • 事件添加到事件处理框架上
    • int event_base_loop(struct event_base *base, int flage);
      • 正常退出返回0,失败返回-1
    • int event_base_dispatch(struct event_base *base);
      • 等同于没有设置标志的event_base_loop()
      • 将一直运行,直到没有已经注册的事件了,或者调用了event_base_loopbreak()或者event_base_loopexit()为止。
    • 循环停止
      • 返回值:成功0,失败-1
  • 开始事件循环
  • 释放资源
    • 释放事件:int event_free(struct event *event);
4. Bufferevent - 数据缓冲区
  • event2/bufferevent.h
  • bufferevent理解:
    • libeverent为IO缓冲区操作提供的一种通用机制
    • bufferevent由一个底层的传输端口(如套接字),一个读取缓冲区和一个写入缓冲区组成。
    • 与通常的事件在底层传输端口已经就绪,可以读取或者
  • 回调 - 缓冲区对应的操作
    • 每个bufferevent有两个数据相关的回调
      • 一个读取回调
        • 从底层端口读取了任意量的数据之后会调用读取回调
      • 一个写入回调
        • 输出缓冲区中足够量的数据被清空到底层传输端口后写入回调会被调用
5.使用bufferevent
  • 创建基于套接字的bufferevent
    • 可以使用bufferevent_socket_new()创建基于套接字的bufferevent
    • struct bufferevent *bufferevent_socket_new( struct event_base *base, event_socket_t fd, enum bufferevent_options options);
      • options:BEV_OPT_CLOSE_ON_FREE
        • 释放bufferevent时关闭底层传输端口。这将关闭底层套接字,释放底层的bufferevent等
        • page53
      • struct bufferevent
      • 成功时返回一个bufferevent,失败返回NULL
  • 在bufferevent上启动链接
    • int bufferevent_socket_connect(struct bufferevent *bev), struct sockaddr *address, int addrlen);
      • address 和 addrlen参数跟标准调用connect()参数相同。如果还没有为bufferevent设置套接字,调用函数将为其分配一个新的流套接字,并且设置为非阻塞
      • 如果已经为bufferevent设置套接字,调用bufferevent_socket_connect将告知libevent套接字还未链接,直到链接成功前不应该对其进行读取和写入操作
      • 链接完成之前可以向输出缓冲区添加数据
  • 释放bufferevent操作
    • void bufferevent_free(struct bufferevent *bev);
  • bufferevent读写缓冲区回调操作
    • typedef void(*bufferevent_data_cb)( struct bufferevent *bev, void *ctx);
    • typedef void(*bufferevent_event_cd)(struct bufferevent *bev, short event, void *ctx);
    • event参数:
      • EV_EVENT_READING:读取操作时发生某事件,具体是哪种事件请看其他标志。
        BEV_EVENT_WRITING:写入操作时发生某事件,具体是哪种事件请看其他标志。
        EVUTIL_SOCKET_ERROR()。
        BEV_EVENT_ERROR:操作时发生错误。关于错误的更多信息,请调 用
        BEV_EVENT_TIMEOUT:发生超时。
        BEV_EVENT_EOF:遇到文件结束指示。
      • BEV_EVENT_CONNECTED:请求的连接过程已经完成
    • void bufferevent_setb(struct bufferevent *bufev, bufferevent_data_cb readcd, bufferevent_data_cb writecd, bufferevent_event_cb eventcb, void *cbarg);
      • readcb:在读回调中读数据
      • writecb:可以设置为NULL
      • eventcb:可以设置为NULL
  • 禁用、启用缓冲区
    • 禁用之后,回调函数不再被调用
    • void bufferevent_enable(struct bufferevent *bufev, short event);
    • void bufferevent_disable(struct bufferevent *bufev, short events);
    • short bufferevent_get_enabled(struct bufferevent *bufev);
  • 操作bufferevent中的数据
    • 向bufferevent的输出缓冲区中添加数据
      • int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);
    • 从bufferevent 的输入缓冲区中移除数据
      • size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
6.链接监听器
  • 创建和释放evconnlistener
    • typedef void(*evconnlistener_cb)(struct evconnlistener *listenner, evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr);
      • sock : 用于通信的文件描述符
      • addr : 客户端的IP和端口信息
      • ptr : 外部传来的数据
    • struct evconnlistener *evconnlistener_new(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, evutil_socket_t fd);
      • 没有包含bind
    • struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,const struct sockaddr *sa, int socklen);
      • cb:接受链接后,用户要做的操作
      • backlog:使用默认的最大值
      • sa:服务器的IP和端口信息
  • 启用和禁用evconnlistener
    • int evconnlistener_disable(struct evconnlistener *lev);
    • int evconnlistener_enable(struct evconnlistener *lev);
  • 调整evconnlistenner
    • void evconnlistener_set_cb(struct evconnlistener *lev, evconnlistener_cb cb,void *arg);
    • 函数调整evconnlistener的回调函数和参数

code-server

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>

// 读缓冲区回调
void read_cb(struct bufferevent *bev, void *arg)
{
    char buf[1024] = {0};   
    bufferevent_read(bev, buf, sizeof(buf));
    char* p = "我已经收到了你发送的数据!";
    printf("client say: %s\n", p);

    // 发数据给客户端
    bufferevent_write(bev, p, strlen(p)+1);
    printf("====== send buf: %s\n", p);
}

// 写缓冲区回调
void write_cb(struct bufferevent *bev, void *arg)
{
    printf("我是写缓冲区的回调函数...\n"); 
}

// 事件
void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
        printf("connection closed\n");  
    }
    else if(events & BEV_EVENT_ERROR)   
    {
        printf("some other error\n");
    }
    
    bufferevent_free(bev);    
    printf("buffevent 资源已经被释放...\n"); 
}



void cb_listener(
        struct evconnlistener *listener, 
        evutil_socket_t fd, 
        struct sockaddr *addr, 
        int len, void *ptr)
{
   printf("connect new client\n");

   struct event_base* base = (struct event_base*)ptr;
   // 通信操作
   // 添加新事件
   struct bufferevent *bev;
   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

   // 给bufferevent缓冲区设置回调
   bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
   bufferevent_enable(bev, EV_READ);
}


int main(int argc, const char* argv[])
{

    // init server 
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    struct event_base* base;
    base = event_base_new();
    // 创建套接字
    // 绑定
    // 接收连接请求
    struct evconnlistener* listener;
    listener = evconnlistener_new_bind(base, cb_listener, base, 
                                  LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 
                                  36, (struct sockaddr*)&serv, sizeof(serv));

    event_base_dispatch(base); 

    evconnlistener_free(listener);
    event_base_free(base);

    return 0;
}

code - client

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>


void read_cb(struct bufferevent *bev, void *arg)
{
    char buf[1024] = {0}; 
    bufferevent_read(bev, buf, sizeof(buf));
    printf("Server say: %s\n", buf);
}

void write_cb(struct bufferevent *bev, void *arg)
{
    printf("I am Write_cb function....\n");
}

void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
        printf("connection closed\n");  
    }
    else if(events & BEV_EVENT_ERROR)   
    {
        printf("some other error\n");
    }
    else if(events & BEV_EVENT_CONNECTED)
    {
        printf("成功连接到服务器, O(∩_∩)O哈哈~\n");
        return;
    }
    
    bufferevent_free(bev);
    printf("free bufferevent...\n");
}

void send_cb(evutil_socket_t fd, short what, void *arg)
{
    char buf[1024] = {0}; 
    struct bufferevent* bev = (struct bufferevent*)arg;
    printf("请输入要发送的数据: \n");
    read(fd, buf, sizeof(buf));
    bufferevent_write(bev, buf, strlen(buf)+1);
}


int main(int argc, const char* argv[])
{
    struct event_base* base;
    base = event_base_new();


    struct bufferevent* bev;
    bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

    // 连接服务器
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    evutil_inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));

    // 设置回调
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    bufferevent_enable(bev, EV_READ | EV_PERSIST);

    // 创建一个事件
    struct event* ev = event_new(base, STDIN_FILENO, 
                                 EV_READ | EV_PERSIST, 
                                 send_cb, bev);
    event_add(ev, NULL);
    
    event_base_dispatch(base);

    event_base_free(base);

    return 0;
}

代码来自黑马视频

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: libevent是一个开源的C语言网络编程库,主要用于处理高并发网络连接。它提供了对事件驱动的支持,使得开发者可以方便地编写高效的并发网络应用程序。 libevent的核心是事件循环机制。在传统的网络编程中,通常需要使用多线程或多进程来处理并发连接,而使用libevent可以通过一个事件循环来处理多个连接。在事件循环中,可以注册多个事件,并定义回调函数来处理事件的触发。当有事件发生时,libevent会调用相应的回调函数来处理事件的处理逻辑。这样可以大大简化并发编程的复杂性,并提高程序的性能。 libevent的事件模型基于操作系统提供的I/O多路复用机制,如select、poll和epoll等。它可以在不同的操作系统平台上运行,并提供一致的接口和高效的事件处理机制。借助这些机制,libevent可以同时处理大量的并发连接,并保持低延迟和高吞吐量。 除了处理网络连接,libevent还提供了其他常用的功能,如定时器和信号处理等。它允许开发者在事件循环中注册定时器事件,可以用于定时任务的调度。同时,libevent还可以处理来自操作系统的信号,并提供了对信号的处理接口,以便开发者能够处理各种系统事件。 总之,libevent是一个功能强大、简单易用的高并发网络编程库,适用于开发各种类型的网络应用。无论是开发服务器、代理、聊天程序还是实时应用,libevent都能帮助开发者快速编写高性能的并发网络程序。 ### 回答2: libevent是一个开源的C/C++网络库,用于高性能的事件驱动编程。它提供了一个轻量级、可移植的框架,用于开发高并发的网络应用程序。 它的设计目标是提供一个高效的事件处理器,可以处理成千上万个并发连接,并且支持多线程并发处理。libevent基于事件驱动模型,通过异步I/O和回调函数来实现高并发处理网络请求。 libevent提供了一系列的函数来注册和监听各种网络事件,包括读、写、超时和信号等等。当一个事件发生时,libevent会调用相应的回调函数来处理事件。通过这种方式,我们可以非常方便地处理并发连接,并实现高性能的网络编程。 libevent的优点主要包括: 1. 高性能:libevent使用异步I/O和事件驱动模型,能够处理成千上万个并发连接,具有很高的处理能力。 2. 可移植性:libevent提供了统一的接口,可以在多种操作系统上运行,包括Linux、Windows、Mac等。 3. 易用性:libevent简单易用,只需注册感兴趣的事件和相应的回调函数,就可以实现高效的网络编程。 4. 多线程支持:libevent支持多线程并发处理,可以充分利用多核CPU的性能优势。 总之,libevent是一款非常适合高并发网络编程的开源库,它可以帮助我们实现高性能的服务器程序,提升系统的并发处理能力。无论是开发网络服务器还是网络应用程序,libevent都是一个不错的选择。 ### 回答3: libevent 是一个用于高并发网络编程的 C/C++ 库。它提供了一个跨平台的异步事件驱动的网络编程框架,能够实现高效地处理大量并发连接的需求。 libevent 的主要特点包括: 1. 异步事件驱动:libevent 使用事件驱动模型,主要利用非阻塞 I/O 和事件回调机制,能够高效地处理大量并发事件。 2. 跨平台支持:libevent 提供了跨不同操作系统的支持,包括 Windows、Linux、Unix 等,并且提供了统一的 API 接口,方便开发者进行跨平台开发。 3. 支持多种网络协议:libevent 支持 TCP、UDP、HTTP 等多种网络协议,为开发者提供了丰富的网络编程能力。 4. 高性能:libevent 的设计目标之一是高性能,它通过使用多路复用技术,将系统资源高效地利用起来,能够同时处理大量并发连接,并且保持低延迟。 5. 灵活易用:libevent 提供了简洁的 API,使用起来非常方便,可以快速实现高并发网络编程的需求。 总之,libevent 是一个强大而灵活的 C/C++ 库,适用于各种需要处理高并发连接的网络应用程序。无论是开发高性能服务器、代理、负载均衡器还是其他类似应用,libevent 都是一个值得推荐的选择。它的高效性能、跨平台支持和简洁易用的 API 接口使得开发者能够快速构建稳定可靠的高并发网络应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值