libevent源码剖析(二)——先使用下

在正式进入libevent源码时,我们先来用一下它。会用然后再问为什么。
libevent提供了一个框架,我们只需要往里面添加细节就可以了。机械人士,就拿汽车来做比喻吧,我就往里面装好发动机就行了:

  1. 拿到差发动机的框架(创建框架)
  2. 拿出发动机(创建事件)
  3. 将发动机装入(添加事件)
  4. 造汽车(事件循环)

我们就根据这个逻辑来使用一下libevent。

一、框架——event_base()

第一步就是框架的创建。

struct event_base* event_base_new(void);

有借有还,再借不难,用了人家的用完了记得还回去。

event_base_free(struct event_base* base);

二、事件创建——event_new()

创建我们要做的事情。

struct event* event_new(
	struct event_base* base,//框架
	evutil_socket_t fd,//文件描述符
	short what,//事情
	event_callback_fn cb,//回调函数
	void* arg//参数
);
typedef void (*event_callback_fn)(evutil_socket_t,short,void*);//对应上面的成员
//	short what
	#define  EV_TIMEOUT         0x01    // 已淘汰(忽略)
	#define  EV_READ            0x02
	#define  EV_WRITE           0x04
	#define  EV_SIGNAL          0x08    //libevent封装了信号相关的操作 SIGNAL
	#define  EV_PERSIST         0x10    // 持续触发
	#define  EV_ET              0x20    // 边沿模式

用完记得还

void event_free(struct event *event);

事件添加——event_add()

创建了事件,你还要将他注册,也就是添加到框架上去。

int event_add(struct event* ev,const struct timeval* tv);//tv为NULL,事件被触发,回调调用,tv为{0,n},时间内触发则调用,否则等时间后调用。 返回0成功,返回-1失败。

事件循环——event_base_dispatch()

最后添加事件循环就可以了。

int event_base_dispatch(struct event_base* base);

这是libevent的基础使用框架,能完成简单的功能。下面继续介绍一下一些重要的函数。

数据缓冲

在读写操作时,libevent提供一个IO通信,bufferevent,是一个实现的端口,有两部分,读缓冲和写缓冲。使用流程:
创建:
bufferevent_socket_new(),由函数就可以看出是一个类似套接字的东西。

struct bufferevent * bufferevent_socket_new(
                     struct event_base *base,
                     evutil_socket_t fd,
                     enum bufferevent_options options
);

函数原型中可以看参数:首先这也是一个event,结构体内有框架,有描述符,option则是相关的操作。
同上面一样,记得释放。

void bufferevent_free(struct bufferevent *buff);

回调函数
bufferevent_setcb(),设置相应的回调函数。

void bufferevent_setcb(
	struct bufferevent *bufev,
	bufferevent_data_cb readcb,//使用 bufferevent_read()读取buff中数据信息
	bufferevent_data_cb writecb,//写回调只是提示你发生出去数据,没有实质作用				      
	bufferevent_event_cb eventcb, 				
	void *cbarg
);

输入输出

int bufferevent_write(
	struct bufferevent *bufev,
	const void *data, 
	size_t size
	);
size_t bufferevent_read(
	struct bufferevent *bufev, 
	void *data, 
	size_t size
	);

连接

客户端自然要有connect操作。

int bufferevent_socket_connect( 
	struct bufferevent *bev,
    struct sockaddr *address,
    int addrlen 
);

bev为前面的结构体,后面则是对应地址和地址长度。

服务端则要进行bind和listen操作。

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

里面的参数很容易懂,之哟有一个listen回调函数,定义如下。

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

之后free

void evconnlistener_free(struct evconnlistener *lev);

例子说话

说了只是一些基础的框架,具体的细节还是要用到是慢慢查,写一个例子就能顺起来了。
我们完成一个客户端和服务端的通讯操作。来看下libevent的作用。

//server.c
#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};//init a buf
	bufferevent_read(bev,buf,sizeof(buf));//buffer read
	printf("recv from client:%s\n",buf);
}

void write_cb(struct bufferevent* bev,void *arg)
{
	printf("server send!");
}

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 is free!\n");
}

void send_cb(evutil_socket_t fd,short what,void* arg);

void cb_listener(struct evconnlistener *listener, 
        evutil_socket_t fd, 
        struct sockaddr *addr, 
        int len, void *ptr){
        printf("new client connect!\n");
        struct event_base *base=(struct event_base*)ptr;
        struct bufferevent* bev;
        bev=bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
        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, 
                                 send_cb, bev);
        event_add(ev,NULL);
        }
void send_cb(evutil_socket_t fd,short what,void* arg)
{
	char buf[1024]={0};
	struct bufferevent* bev=(struct bufferevent*)arg;
	printf("input:");
	read(fd,buf,sizeof(buf));
	bufferevent_write(bev,buf,strlen(buf)+1);
}

//调用框架就可以了
int main(int argc,const char* argv[])
{
	struct sockaddr_in ser;
	memset(&ser,0,sizeof(ser));
	ser.sin_family=AF_INET;
	ser.sin_port=htons(9876);
	ser.sin_addr.s_addr=htonl(INADDR_ANY);

	struct event_base *base;
	base=eventbase_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;
}
//client.c
#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("recv from server: %s\n", buf);
}
 
void write_cb(struct bufferevent *bev, void *arg)
{
   printf("client send!\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("connect ok!\n");
        return;
    }
    
    bufferevent_free(bev);
    printf("bufferevent free!\n");
}
 
void send_cb(evutil_socket_t fd, short what, void *arg)
{
    char buf[1024] = {0}; 
    struct bufferevent* bev = (struct bufferevent*)arg;
    printf("input: \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;
}

也算是个很大的工程了,顺便回忆了socket的一些操作。可以看到,使用libevent时,只需要自己设置好自己想要的操作,然后套用框架就可以了。
之后,继续分析libevent的源码,看看这些框架为什么可以实现这些操纵。
文中很多参数没有介绍,可以在使用时自行查阅libevent相关参数就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值