libevent案例

常规事件

server


#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <event2/event.h>

void read_cb(evutil_socket_t fd, short what, void *arg) {
    char buf[1024];
    int len = read(fd, buf, sizeof(buf));
    printf("%s \n", what & EV_READ ? "yes" : "no");
    printf("%s %d \n", buf, len);
    sleep(1);
}

int main() {
    unlink("myfifo");
    mkfifo("myfifo", 0664);
    /**
     * 获取读权限,设置非阻塞.
     * 这里之所以非阻塞是因为libevent是基于事件异步的通行模型,主要异步执行回调函数.
     */
    int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
    //创建event_base,类似于epoll红黑树根节点
    struct event_base *base = event_base_new();

    /**
     * 创建事件
     * fd表示绑定到 创建的ev 上的文件描述符
     * EV_READ 一次读事件
     * EV_WRITE 一次写事件
     * EV_PERSIST 持续触发,需要结合event_base_dispatch使用,才生效.不指定,则只执行一次
     * read_cb满足事件监听的回调函数
     *
     * void read_cb(evutil_socket_t fd, short what, void *arg)
     *  fd 对应这里的fd
     *  what 对应这里的EV_READ | EV_PERSIST
     *  arg 对应最后一个参数NULL
     */
    struct event *ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);

    /**
     * 添加一个[常规事件]到event_base
     * timeout:设置超时时间
     *      NULL:不会超时,等到事件被触发,回调函数立刻执行
     *      非0:期间检查事件有没有触发,一旦时间到则事件会被回调.
     */
    event_add(ev, NULL);

    /**
     * 从event_base删除事件
     *
     */
    //event_del(ev);

    //事件循环 可理解为while(1) epoll_wait()
    event_base_dispatch(base);
    //指定时间后停止
//    event_base_loopexit()
    //立即停止
//    event_base_loopbreak()

    //销毁添加的事件
    event_free(ev);
    //销毁event_base
    event_base_free(base);
    close(fd);
    return 0;
}

client

#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>

void write_cb(evutil_socket_t fd, short what, void *arg) {
    char buf[1024] = "hello";
    static int num = 0;
    sprintf(buf, "hello world %d\n", num++);
    printf("%s", buf);
    write(fd, buf, strlen(buf) + 1);
    sleep(1);
}

int main() {
    int fd = open("myfifo", O_WRONLY | O_NONBLOCK);
    //创建event_base
    struct event_base *base = event_base_new();
    //创建事件
    struct event *ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);

    //添加事件
    event_add(ev, NULL);

    //事件循环
    event_base_dispatch(base);

    //销毁添加的事件
    event_free(ev);
    //销毁event_base
    event_base_free(base);
    close(fd);
    return 0;
}

缓冲事件

server

#include <sys/stat.h>
#include <string.h>
#include<event2/bufferevent.h>
#include <event2/event.h>
#include <event2/listener.h>

#define  PORT 8080

/**
 * 缓冲事件
 *      有2个缓冲区,队列实现.
 */
void read_cb(struct bufferevent *bev, void *ctx) {
    char buf[1024];
    //从读缓存中读取数据
    bufferevent_read(bev, buf, sizeof(buf));
    printf("client say : %s \n", buf);
    char *p = "world";
    //向写缓存中写数据,一旦有数据就会自动刷新,发送给对端,发送成功后,会被通知写回调方法.
    bufferevent_write(bev, p, strlen(p) + 1);
}

void write_cb(struct bufferevent *bev, void *ctx) {
    printf("发送成功 \n");
}

/**
 * 事件回调
 * @param bev
 *
 * @param what
 *          不同标志位,表示不同事件
           BEV_EVENT_READING    读缓冲区满足,则产生事件
           BEV_EVENT_WRITING	写缓冲区满足,则产生事件
           BEV_EVENT_EOF		读到文件结尾
           BEV_EVENT_ERROR		出错,则产生事件
           BEV_EVENT_TIMEOUT	超时
           BEV_EVENT_CONNECTED  请求的连接过程完成,客户端时可用
 *
 * @param ctx   回调函数参数
 */
void event_cb(struct bufferevent *bev, short what, void *ctx) {
    if (what & BEV_EVENT_EOF) {
        printf("connection closed \n");
    } else if (what & BEV_EVENT_ERROR) {
        printf("error \n");
    }
    bufferevent_free(bev);
    printf("资源释放 \n");
}

/**
 * 客户端连接后,回调
 * @param listener    当调用evconnlistener_new_bind返回的监听器
 * @param fd          客户端的套接字
 * @param addr        客户端地址
 * @param len         客户端地址长度
 * @param ptr         当调用evconnlistener_new_bind设置的参数
 */
void cb_listener(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int len, void *ptr) {
    struct event_base *base = (struct event_base *) ptr;
    /**
     * 创建bufferevent
     * struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
     * base     event_base_new()返回值
     * fd       跟bufferevent绑定的fd
     * options
     *      BEV_OPT_CLOSE_ON_FREE:释放bufferevent时关闭底层传输端口,也就是关闭底层套接字,释放底层bufferevent等
     */
    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
//    bufferevent_free() 释放缓冲事件

/**
 * 给bufferevent设置回调
void bufferevent_setcb(struct bufferevent *bufev,
    bufferevent_data_cb readcb, bufferevent_data_cb writecb,
    bufferevent_event_cb eventcb, void *cbarg);

    bufev    : bufferevent_socket_new返回值
    readcb    :读回调,不用传NULL即可
    writecb     :写事件满足时回调
    eventcb     :事件回调
    cbarg       :回调函数所有参数
 *
 */
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);


    /**
     * 启用缓冲区
     * 默认写缓冲是启用的,读缓冲没启用
     */
    bufferevent_enable(bev, EV_READ);
    //禁用缓冲区
//    bufferevent_disable(bev, EV_READ);
    //获取缓冲区禁用状态,可通过&判断
//    bufferevent_get_enabled(bev);

}

int main() {
    struct sockaddr_in serv_addr;

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    struct event_base *base = event_base_new();

    /**
     * 相当于socket,bind,listen,accept
     * 创建套接字,绑定,接收连接请求
     * struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
        evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
        const struct sockaddr *sa, int socklen);

     * base         :   event_base_new()返回值
     * cb           :   接受连接之后,回调函数
     * ptr          :   回调函数参数
     * flags        :
     *                  LEV_OPT_CLOSE_ON_FREE  释放bufferevent时关闭底层传输端口,也就是关闭底层套接字,释放底层bufferevent等
     *                  LEV_OPT_REUSEABLE     端口复用
     * backlog      :   listen的第二个参数, -1表示默认最大值
     * sa / socklen     :   传给bind的参数   服务器的ip+port 以及长度
     */
    struct evconnlistener *listener = evconnlistener_new_bind(base, cb_listener, base,
                                                              LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 36,
                                                              (struct sockaddr *) &serv_addr, sizeof(serv_addr));

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_base_free(base);
    return 0;
}

client

#include <string.h>
#include<event2/bufferevent.h>
#include <event2/event.h>
#include <arpa/inet.h>
#include <unistd.h>

#define  PORT 8080

void read_cb(struct bufferevent *bev, void *ctx) {
    char buf[1024];
    bufferevent_read(bev, buf, sizeof(buf));
    printf("server say : %s \n", buf);
    bufferevent_write(bev, buf, strlen(buf) + 1);
    sleep(1);
}

void write_cb(struct bufferevent *bev, void *ctx) {
    printf("发送成功 \n");
}

void event_cb(struct bufferevent *bev, short what, void *ctx) {
    if (what & BEV_EVENT_EOF) {
        printf("connection closed \n");
    } else if (what & BEV_EVENT_ERROR) {
        printf("error \n");
    } else if (what & BEV_EVENT_CONNECTED) {
        printf("已经连接服务器 \n");
        return;
    }
    bufferevent_free(bev);
    printf("资源释放 \n");
}

void read_terminal(evutil_socket_t fd, short what, void *arg) {
    char buf[1024] = {0};
    int len = read(fd, buf, sizeof(buf));
    struct bufferevent *bev = (struct bufferevent *) arg;
    printf("terminal rev : %s \n", buf);
    bufferevent_write(bev, buf, len + 1);
}

int main() {
    struct sockaddr_in serv_addr;

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

    int fd = socket(AF_INET, SOCK_STREAM, 0);

    struct event_base *base = event_base_new();
    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

    /**
     * int bufferevent_socket_connect(struct bufferevent *bufferevent, struct sockaddr * addr, int len);
     * bufferevent        事件对象(封装了fd)
     * addr / len         等同于connect的addr和len参数
     */
    bufferevent_socket_connect(bev, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    bufferevent_enable(bev, EV_READ);

    struct event *ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, read_terminal, bev);
    event_add(ev, NULL);

    event_base_dispatch(base);

    event_free(ev);
    event_base_free(base);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于学习libevent,你可以按照以下步骤进行: 1. 了解libeventlibevent是一个开源的事件通知库,它提供了事件驱动的网络编程接口,可以用于开发高性能的网络服务器和客户端应用。它支持多种I/O模型(包括基于事件的和多线程的),并提供了跨平台的兼容性。 2. 安装libevent:你可以从libevent的官方网站(https://libevent.org/)上下载最新版本的libevent,并按照官方文档中的指南进行安装。根据你使用的操作系统不同,安装步骤可能会有所不同。 3. 学习libevent的基本概念:了解libevent中的一些核心概念,如事件循环(event loop)、事件处理器(event handler)、事件回调函数(event callback)等。理解这些概念对于正确使用libevent非常重要。 4. 掌握libevent的使用方法:学习如何使用libevent来编写网络应用程序。这包括创建事件循环、注册事件、定义事件回调函数等。libevent提供了丰富的API,你可以根据自己的需求选择合适的接口进行开发。 5. 深入研究libevent的高级特性:学习libevent的更高级功能,如定时器、信号处理、缓冲区管理等。这些功能可以帮助你更好地控制和优化你的网络应用。 6. 查阅文档和示例代码:libevent的官方网站提供了详细的文档和示例代码,你可以利用这些资源来加深对libevent的理解。此外,还可以参考一些开源项目中使用libevent的实际案例,以便更好地应用于自己的项目中。 记住,学习任何新的库或工具都需要有耐心和实践。不断尝试和练习,结合实际项目,才能更好地掌握和应用libevent。祝你学习顺利!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值