libevent入门

安装

下载

管网
找到合适的版本,并击下载,解压到合适的地方

tar -xzvf libevent-xxx.tar.gz

编译和安装

./configure
make
sudo make install

文档

官方给的文档,打不开,为此在github找到了文档的项目,clone并编译即可
git地址

https://gitee.com/cocosleep/libevent-book.git

编译

编译之前还需要安装 asciidoc

suod apt install asciidoc
make

编译之后生成很多html文件,把它们移动到一个指定的空文件

mv *.html html/

TOC.html就是整个文档的索引。

基于 event_base的 tcp 服务器框架

创建销毁 event_base

struct event_base* event_base_new(void);
void event_base_free(struct event_base* event);

添加监听节点

#define EV_TIMEOUT   0x01
#define EV_READ      0x02
#define EV_WRITE     0x04
#define EV_SIGNAL    0x08
#define EV_PERSIST   0x10
#define EV_ET        0x20 
typedef void(*event_callback_fn)(int fd, short event, void* arg);
struct event* event_new(struct event_base* base, int fd, short event, env_callback_fn cb, void* arg);
void *event_self_cbarg();
// 用法
// event_new(base, 0, EV_READ|EV_PERSIST, cb, event_self_cbarg());
int event_add(struct event* ev, const struct timeval* tv);
int event_del(struct event* ev);
/*
* 先调用 event_del 然后再free
 */
void event_free(struct event* event);

事始事件循环

int event_base_despatch(struct event_base* event);

例子

#include <stdio.h>
#include <event.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int ipv4bind(short port, const char* ip)
{
    struct sockaddr_in sin;
    sin.sin_addr.s_addr = 0;
    if(ip != NULL)
    {
        inet_aton(ip, &sin.sin_addr);
    }
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1)
    {
        return -1;
    }
    int val = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
    if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        close(fd);
        fprintf(stderr, "bind error\n");
        return -1;
    }
    return fd;
}
void read_cb(int fd, short event, void* arg)
{
    struct event* ev = (struct event*) arg;
    char buf[1500];
    int nRead = read(fd, buf, 1500);
    if(nRead <= 0)
    {
        event_free(ev);
        return;
    }
    write(fd, buf, nRead);
}
void accept_cb(int fd, short event, void* arg)
{
    printf("accept \n");
    struct event_base* base = (struct event_base* ) arg;
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    socklen_t len = sizeof(sin);
    int cfd = accept(fd,(struct sockaddr*)&sin, &len);
    if(cfd == -1)
    {
        fprintf(stderr, "accept error \n");
        return;
    }
    struct event* ev = event_new(base, cfd, EV_READ|EV_PERSIST, read_cb, event_self_cbarg());
    event_add(ev, NULL);
    const char* msg = "Hello client\n";
    write(cfd, msg, strlen(msg));
}
int main()
{
    struct event_base* base = event_base_new();
    if(base == NULL)
    {
        fprintf(stderr, "event_base_new error\n");
        return 1;
    }
    int fd = ipv4bind(8888, NULL);
    if(fd == -1)
    {
        fprintf(stderr, "error ivp4bind\n");
        return 1;
    }
    if(listen(fd, 128)==1)
    {
        fprintf(stderr, "listen error\n");
        return 1;
    }
    struct event* ev = event_new(base,fd, EV_READ|EV_PERSIST,accept_cb, base);
    event_add(ev, NULL);
    event_base_dispatch(base);
    event_free(ev);
    event_base_free(base);
    return 0;
}

bufferevent

事件标志

BEV_EVENT_READING
BEV_EVENT_WRITING
BEV_EVENT_ERROR -- EVUTIL_SOCKET_ERROR() 获取错信息
BEV_EVENT_TIMEOUT
BEV_EVENT_EOF
BEV_EVENT_CONNECTED

bufferevents标志选项

BEV_OPT_CLOSE_ON_FREE
BEV_OPT_THREADSAFE
BEV_OPT_DEFER_CALLBACKS
BEV_OPT_UNLOCK_CALLBACKS
truct bufferevent *bufferevent_socket_new(
    struct event_base *base,
    evutil_socket_t fd,
    enum bufferevent_options options);

可以给fd指定-1,之后通过 bufferevent_setfd设置
创建bufferevent之后可以给它指定一些回调函数

typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
typedef void (*bufferevent_event_cb)(struct bufferevent *bev,
    short events, void *ctx);

void bufferevent_setcb(struct bufferevent *bufev,
    bufferevent_data_cb readcb, bufferevent_data_cb writecb,
    bufferevent_event_cb eventcb, void *cbarg);

事件的使能配置

void bufferevent_enable(struct bufferevent *bufev, short events);
void bufferevent_disable(struct bufferevent *bufev, short events);

short bufferevent_get_enabled(struct bufferevent *bufev);

events 选项

EV_READ
EV_WRITE

释放 bufferevent

void bufferevent_free(struct bufferevent *bev);

如果在创建时指定了BEV_OPT_CLOSE_ON_FREE,释放时会关闭对应的fd

例子

#include <stdio.h>
#include <event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int ipv4bind(short port, const char* ip)
{
    struct sockaddr_in sin;
    sin.sin_addr.s_addr = 0;
    if(ip != NULL)
    {
        inet_aton(ip, &sin.sin_addr);
    }
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1)
    {
        return -1;
    }
    int val = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
    if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
    {
        close(fd);
        fprintf(stderr, "bind error\n");
        return -1;
    }
    return fd;
}
void readcb(struct bufferevent* bev, void* arg)
{
    // 还有更多的 bufferevent_函数
    char buf[1500];
    int nRead = bufferevent_read(bev, buf, 1500);
    bufferevent_write(bev, buf, nRead);
}
void eventcb(struct bufferevent* bev, short event, void* arg)
{
    if(event & BEV_EVENT_EOF)
    {
        printf("close \n");
        bufferevent_free(bev);
    }
    if(event & BEV_EVENT_CONNECTED)
    {
        printf("connected \n");
    }
}
void acceptcb(int fd, short event, void* ctx)
{
    struct event_base* base = (struct event_base*)ctx;
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    socklen_t len = sizeof(sin);
    int cfd = accept(fd, (struct sockaddr*)&sin, &len);
    if(cfd != -1)
    {
        // bufferevent 提供内置缓冲区,要吧更方便的进行数据读写
        struct bufferevent* cbev = bufferevent_socket_new(base, cfd, BEV_OPT_CLOSE_ON_FREE);
        if(cbev == NULL)
        {
            printf("error \n");
        }
        bufferevent_setcb(cbev, readcb, NULL, eventcb, NULL);
        bufferevent_enable(cbev, EV_READ);
    }
}
int main()
{
    struct event_base* base = event_base_new();
    if(base == NULL)
    {
        return 1;
    }
    int fd = ipv4bind(8888, NULL);
    listen(fd, 128);
    // 这个没有读写操作,使用bufferevent没有意义
    struct event* ev = event_new(base, fd, EV_READ|EV_PERSIST, acceptcb, base);
    event_add(ev, NULL);
    event_base_dispatch(base);
    event_base_free(base);
}

TCP连接侦听器

struct evconnlistener *evconnlistener_new(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    evutil_socket_t fd);
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    const struct sockaddr *sa, int socklen);
void evconnlistener_free(struct evconnlistener *lev);

flags可以取以下值

LEV_OPT_LEAVE_SOCKETS_BLOCKING
  默认创建的socket是非阻塞的
LEV_OPT_CLOSE_ON_FREE
  释放时关闭
LEV_OPT_CLOSE_ON_EXEC
  执行exec函数时关闭
LEV_OPT_REUSEABLE
  复用?
LEV_OPT_THREADSAFE
  线程完全
LEV_OPT_DISABLED
  创建时使用其无效, 可以用 evconnlistener_enable() 为其使用能

监听器的回调函数

typedef void (*evconnlistener_cb)(struct evconnlistener *listener,
    evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr);

设置监听回调函数

int evconnlistener_disable(struct evconnlistener *lev);
int evconnlistener_enable(struct evconnlistener *lev);

错误回调

typedef void (*evconnlistener_errorcb)(struct evconnlistener *lis, void *ptr);
void evconnlistener_set_error_cb(struct evconnlistener *lev,
    evconnlistener_errorcb errorcb);

使用能函数

int evconnlistener_disable(struct evconnlistener *lev);
int evconnlistener_enable(struct evconnlistener *lev);

获取数据

evutil_socket_t evconnlistener_get_fd(struct evconnlistener *lev);
struct event_base *evconnlistener_get_base(struct evconnlistener *lev);

使用TCP侦听连接器

#include <stdio.h>
#include <event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
void readcb(struct bufferevent* bev, void* arg)
{
    printf("read \n");
    char buf[1500];
    int nRead = bufferevent_read(bev, buf, 1500);
    bufferevent_write(bev, buf, nRead);
}
void eventcb(struct bufferevent* bev, short event, void* arg)
{
    if(event & BEV_EVENT_EOF)
    {
        printf("close \n");
        bufferevent_free(bev);
    }
    if(event & BEV_EVENT_CONNECTED)
    {
        printf("connected \n");
    }
}
void listen_cb(struct evconnlistener* listen, int fd, struct sockaddr* addr, int len, void* ctx)
{
    struct event_base* base = evconnlistener_get_base(listen);
    struct sockaddr_in sin;
    struct bufferevent* cbev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    if(cbev == NULL)
    {
        printf("error \n");
    }
    bufferevent_setcb(cbev, readcb, NULL, eventcb, NULL);
    bufferevent_enable(cbev, EV_READ);
}
int main()
{
    struct event_base* base = event_base_new();
    if(base == NULL)
    {
        return 1;
    }
    struct sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_port = htons(8888);
    sa.sin_addr.s_addr = 0;
    struct evconnlistener* listener = evconnlistener_new_bind(
                                                              base, listen_cb, NULL,
                                                              LEV_OPT_CLOSE_ON_FREE,
                                                              -1, (struct sockaddr*)&sa, sizeof(sa)
                                                             );
    event_base_dispatch(base);
    event_base_free(base);
}

tcp客户端

int bufferevent_socket_connect(struct bufferevent* bev, struct socketaddr* addr, int addrlen);
#include <stdio.h>
#include <event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
void readcb(struct bufferevent* bev, void* ctx)
{
    char buf[1500];
    int nRead = bufferevent_read(bev, buf, 1500);
    write(STDOUT_FILENO, buf, nRead);
}
void eventcb(struct bufferevent* bev, short events, void* ctx)
{
    if(events & BEV_EVENT_EOF)
    {
        printf("closed \n");
        bufferevent_free(bev);
    }
    if(events & BEV_EVENT_CONNECTED)
    {
        printf("connected\n");
    }
}
void in_eventcb(int fd, short events, void* ctx)
{
    struct bufferevent* bev = (struct bufferevent*)ctx;
    char buf[1500];
    int nRead = read(fd, buf, 1500);
    bufferevent_write(bev, buf, nRead);
}
int main()
{
    struct event_base* base = event_base_new();
    if(base == NULL)
    {
        return 1;
    }
    struct bufferevent* bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, readcb, NULL, eventcb, NULL);
    bufferevent_enable(bev, EV_READ);
    struct sockaddr_in sa;
    sa.sin_port = htons(8888);
    sa.sin_family = AF_INET;
    inet_aton("127.0.0.1", &sa.sin_addr);
    bufferevent_socket_connect(bev, (struct sockaddr*)&sa, sizeof(sa));
    struct event* ev = event_new(base, STDIN_FILENO, EV_READ|EV_PERSIST, in_eventcb, bev);
    event_add(ev, NULL);
    event_base_dispatch(base);
    event_base_free(base);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值