Libevent学习记录(4)

Libevent常用API:

三、监听器evconnlistener相关API

1、evconnlistener_new_bind

用户只需初始化struct sockaddr_in结构体变量,然后把它作为参数传给函数evconnlistener_new_bind即可。该函数会完成对socket、bind、listen、accept的一个封装。

函数功能:分配一个监听器对象,监听给定地址上的TCP连接 
	函数原型:
	EVENT2_EXPORT_SYMBOL
	struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
	    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
	    const struct sockaddr *sa, int socklen);
	参数说明:
	   @param base 关联的libevent框架上下文.
	   @param cb 当新连接到来时,进行回调的函数.如果函数为NULL,监听器按被禁用运行,知道函数被设置为非NULL值.
	   @param ptr 提供给回调函数的参数指针,(一般传递base,以便监听回调中使用)
	   @param flags 任意LEV_OPT_*的标识,有下面这些:
			LEV_OPT_LEAVE_SOCKETS_BLOCKING:默认情况下,当连接监听器接收到新的客户端socket连接后,会把该socket设置为非阻塞的。如果设置该选项,那么就把之客户端socket保留为阻塞的
			LEV_OPT_CLOSE_ON_FREE:当连接监听器释放时,会自动关闭底层的socket
			LEV_OPT_CLOSE_ON_EXEC:为底层的socket设置close-on-exec标志
			LEV_OPT_REUSEABLE: 在某些平台,默认情况下当一个监听socket被关闭时,其他socket不能马上绑定到同一个端口,要等一会儿才行。设置该标志后,Libevent会把该socket设置成reuseable。这样,关闭该socket后,其他socket就能马上使用同一个端口
			LEV_OPT_THREADSAFE:为连接监听器分配锁。这样可以确保线程安全
	   @param backlog 类似于listen函数的backlog参数,设置为-1则使用默认设置.
	   @param addr 监听器监听地址.
	   @param socklen 监听器监听地址的字节长度.
备注:这个函数相当于完成系统调用socket()、bind()、listen(),并设置accept回调函数

2、evconnlistener_cb监听回调函数原型:

当监听器监听到一个新连接的时候进行回调(应该是socket的accept成功返回有效的socket描述符后,进行回调,其中fd对应accept返回的文件描述符值).

函数原型:
typedef void (*evconnlistener_cb)(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data);
参数说明:
   @param listener 事件监听器
   @param fd 新的文件描述符,相当于服务器创建的与客户端通信的socket描述符
   @param addr 客户端地址
   @param socklen 客户端地址字节数
   @param user_arg  evconnlistener_new()中传入的自定义参数

四、evBuffer介绍

BufferEvent在进行读取和写入数据时,将数据存放在evBuffer中,因此,要想获取数据的相关信息—>需要对evBuffer结构进行解析。
1.evbuffer以队列的形式管理字节,从尾部添加,从头部取出(FIFO)
2.evbuffer内部存储形式是多个独立的连续内存

1、struct evbuffer* 变量的赋值2种方式

方式1:手动创建+手动向evbuffer中添加数据

struct evbuffer* evbuf = evbuffer_new();  //手动创建evbuffer
evbuffer_add(evbuf,"I am a student",100); //手动将字符串添加到evbuf中
evbuffer_add_printf(evbuf,"%s,%s,%d","Tom","Student",24); //手动将字符串格式化添加到evbuf中
...  ... 
evbuffer_free(evbuf); //手动释放evbuffer

方式2:bufferevent_get_input/output–>获取输入/输出evbuffer

struct evbuffer *input =bufferevent_get_input(bev);   //获取输入evbuffer
struct evbuffer *output =bufferevent_get_output(bev); //获取输出evbuffer

注意:
bufferevent_get_input/bufferevent_get_output只是获取输入/输出缓冲区中的数据,并没有将数据从evbuffer中移走。
而,bufferevent_write是真正的向输出缓冲区中写入数据;bufferevent_read是真正的读走输入缓冲区中的数据。

2、与evbuffer相关的常用函数API

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、数据缓冲bufferevent相关API

bufferevent其实也就是在event_base的基础上再进行一层封装,其本质还是离不开event和event_base,从bufferevent的结构体就可以看到这一点。

bufferevent结构体中有两个event,分别用来监听同一个fd的可读事件和可写事件。由于socket 是全双工的,所以在bufferevent结构体中,也有两个evbuffer成员,分别是读缓冲区和写缓冲区。在这里插入图片描述

1、创建基于套接字的bufferevent:bufferevent_socket_new

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

返回值:成功返回一个bufferevent,失败返回NULL

参数:
base:event_base
fd:表示套接字的文件描述符(如果想以后设置文件描述符,则设置fd为-1)
options: bufferevent 选项的位掩码(bufferevent选项标志)
在这里插入图片描述

2、释放bufferevent:bufferevent_free

void bufferevent_free(struct bufferevent *bev);

bufferevent内部具有引用计数 (如果释放时还有未决的延迟回调,则在回调完成之前bufferevent不会被删除)
如果设置了 BEV_OPT_CLOSE_ON_FREE 标志,并且 bufferevent 有一个套接字或者底层 bufferevent 作为其传输端口,则释放 bufferevent 将关闭这个传输端口

3、设置回调函数:bufferevent_setcb

void bufferevent_setcb( //给bufev设置回调函数、回调函数参数
	struct bufferevent *bufev,
	bufferevent_data_cb readcb, //已经读取足够的数据时被回调
	bufferevent_data_cb writecb, //已经写入足够的数据时被回调
	bufferevent_event_cb eventcb, //发生错误时被回调
	void *cbarg //用户提供的 cbarg 参数
	);

回调函数原型:
当相应的事件到来时,会触发相应的回调函数,此时回调函数的参数已经会被自动赋值

typedef void (*bufferevent_data_cb)( 
	struct bufferevent *bev, //触发了的事件bufferevent
	void  *ctx  //调用bufferevent_setcb()时用户提供的 cbarg 参数
	);
	
typedef void (*bufferevent_event_cb)(
	struct bufferevent *bev,
	short events, //一个表示事件标志的位掩码
	void *ctx
    );

4、启用bufferevent_enable / 禁用bufferevent_disable

默认情况下,新创建的bufferevent的写入EV_WRITE 是启用的,读取EV_READ是没有启用的。
可以启用或者禁用 bufferevent 上的 EV_READ、EV_WRITE 或者 EV_READ | EV_WRITE 事件。
没有启用读取或者写入事件时, bufferevent 将不会试图进行数据读取或者写入。

void bufferevent_enable(  //启用bufev上的events事件
	struct bufferevent *bufev, 
	short events		//events:EV_READ、EV_WRITE 或 EV_READ | EV_WRITE
	);
void bufferevent_disable( //禁用bufev上的events事件
	struct bufferevent *bufev, `在这里插入代码片`
	short events
	);
	
short bufferevent_get_enabled( //获取 bufferevent 上当前启用的事件
	struct bufferevent *bufev
	);

5、向bufferevent的输出缓冲区添加数据(write)

//从data处开始的size字节数据从内存中移除,并添加到输出缓冲区的末尾
int bufferevent_write(
	struct bufferevent *bufev,
	const void *data, 
	size_t size
	);
//将buf中的所有内容从内存中移除,并添加到输出缓冲区的末尾
int bufferevent_write_buffer(
	struct bufferevent *bufev,
	struct evbuffer *buf
	);

成功时,都返回 0;发生错误时,则返回-1

6、从bufferevent的输入缓冲区移除数据(read)

//至多从输入缓冲区bufev移除 size 字节的数据,将其存储到内存中 data 处
//返回值:实际移除的字节数
//注意,对于 bufferevent_read(),data 处的内存块必须有足够的空间容纳 size 字节数据。
size_t bufferevent_read(
	struct bufferevent *bufev, 
	void *data, 
	size_t size
	);
	
//抽空输入缓冲区bufev的所有内容,将其放置到 buf 中
//成功时,都返回 0;发生错误/失败时,则返回-1
int bufferevent_read_buffer(
	struct bufferevent *bufev,
	struct evbuffer *buf
	);

7、基于socket的bufferevent进行connect()连接bufferevent_socket_connect

用户可以在调用bufferevent_socket_new函数时,传一个-1作为socket的文件描述符,然后调用bufferevent_socket_connect函数连接服务器,无需自己写代码调用connect函数连接服务器。
bufferevent_socket_connect函数会调用socket函数申请一个套接字fd,然后把这个fd设置成非阻塞。接着就connect服务器,因为该socket fd是非阻塞的,所以不会等待,而是马上返回,连接这工作交给内核来完成。所以,返回后这个socket还没有真正连接上服务器。那么什么时候连接上呢?内核又是怎么通知通知用户呢?
一般来说,当可以往socket fd可写,那就说明已经连接上了。也就是说这个socket fd变成可写状态,就连接上了。

函数功能:  使用基于socket的bufferevent进行connect()连接
函数原型:int bufferevent_socket_connect(struct bufferevent *bev, const struct sockaddr *sa, int socklen)
函数描述:
   当连接成功时eventcb会被回调 ,使用BEV_EVENT_CONNECTED 集合.内部使用evutil_socket_connect_
   内部使用连接函数原型为:int evutil_socket_connect_(evutil_socket_t *fd_ptr, const struct sockaddr *sa, int socklen)

   (1)如果bufferevent还没有socket set, 则分配一个socket,并且设置为非阻塞
   实现代码中:
   fd = bufferevent_getfd(bev);
	if (fd < 0) {
		if (!sa)
			goto done;
		fd = evutil_socket_(sa->sa_family,
		    SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0);
		if (fd < 0)
			goto freesock;
		ownfd = 1;
	}
   (2)内部使用evutil_socket_connect_函数进行连接,此函数返回值:
2 :连接被拒绝(errno值为ECONNREFUSED)
1 :已经连接上
0 :尚未连接上(errno值为EINTR或则EINPROGRESS),
-1 发生错误
    (3) 根据evutil_socket_connect_返回值,进一步判断,
if (r == 0) {
		if (! be_socket_enable(bev, EV_WRITE)) {
			bufev_p->connecting = 1;
			result = 0;
			goto done;
		}
	} else if (r == 1) {
		/* The connect succeeded already. How very BSD of it. */
		result = 0;
		bufev_p->connecting = 1;
		bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);
	} else {
		/* The connect failed already.  How very BSD of it. */
		result = 0;
		bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS);
		bufferevent_disable(bev, EV_WRITE|EV_READ);
	}
     a)若尚未连接上(errno值为EINTR或则EINPROGRESS),则设置为正在连接标识,并添加一个EV_WRITE事件(超时参数根据bufferevent当前设置的数值),并标记返回值为0(按成功返回),后续若连接上时,会调用事件回调,events值为:BEV_EVENT_CONNECTED,若发生错误,则events值为BEV_EVENT_ERROR
     b)若已经连接上,设置返回成功,同时也是标记正在连接,并直接调用可写回调函数(bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS);)。调用bufferevent_socket_new方法中添加bufferevent事件内部的ev_write事件对应的回调函数bufferevent_writecb
	在bufferevent_writecb回调中,根据connecting结合查询socket当前的连接状态,若已经连接上,则清除connecting为0,并执行事件回调,events值为:BEV_EVENT_CONNECTED。
        若在bufferevent_writecb回调过程中查询到socket连接状态是出错状态,执行事件回调,events值为:BEV_EVENT_ERROR。 
     c)若连接被拒绝,设置返回成功,并调用错误事件回调函数,同时禁用读写缓存;
     d)若发生错误,设置返回失败;
    
参数说明:
   @param bufev 通过bufferevent_socket_new()创建的bufferevent  
   @param addr  服务器地址
   @param socklen 服务器地址长度
返回:
   @return 0 连接成功, -1 :失败.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值