libevent (三) 事件注册与循环监听
事件注册与循环监听
在libevent中为了监听某种事件的发生,设置事件触发后的回调函数,也就是说对该事件注册到当前的IO模型中。
事件注册
事件初始化
使用`event_new`函数来对事件进行初始化。
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);/* 回调函数 */ struct event *event_new(struct event_base *base, evutil_socket_t fd,
short what, event_callback_fn cb,
void *arg); void event_free(struct event *event);
/*
* base:event_base类型,event_base_new的返回值
* fd:监听的fd,listen的fd
* what:事件的类型及属性
* cb:绑定的回调函数
* arg:给回调函数的参数
*/
其中,事件类型及属性如下:
#define EV_TIMEOUT 0x01 /*定时事件*/
#define EV_READ 0x02 /*I/O事件*/
#define EV_WRITE 0x04 /*I/O事件*/
#define EV_SIGNAL 0x08 /*信号*/
#define EV_PERSIST 0x10 /*永久事件 */
#define EV_ET 0x20 /*边沿触发*/
此外,还有一个函数`event_assgin`,它多了一个event参数:
int event_assign(struct event *event, struct event_base *base,
evutil_socket_t fd, short what,
void (*callback)(evutil_socket_t, short, void *), void *arg);
注册事件
虽然已经初始化了事件,但是该事件并不会被触发,原因在于我们并没有激活该事件。
`event_add`函数提供了激活事件的功能。
int event_add(struct event *ev, const struct timeval *tv);
如果是一个(non-pending)未注册`ev`,调用`event_add`函数会注册该事件(变为pending状态)。如果是一个(pending)注册过的`ev`,调用该函数会在tv时间后重新注册该事件。成功返回0,失败返回-1。
例子
#include <event2/event.h> void cb_func(evutil_socket_t fd, short what, void *arg)
{
const char *data = arg;
printf("Got an event on socket %d:%s%s%s%s [%s]",
(int) fd,
(what&EV_TIMEOUT) ? " timeout" : "",
(what&EV_READ) ? " read" : "",
(what&EV_WRITE) ? " write" : "",
(what&EV_SIGNAL) ? " signal" : "",
data);
} void main_loop(evutil_socket_t fd1, evutil_socket_t fd2)
{
struct event *ev1, *ev2;
struct timeval five_seconds = {,};
struct event_base *base = event_base_new(); /* The caller has already set up fd1, fd2 somehow, and make them
nonblocking. */
/* 初始化事件 */
ev1 = event_new(base, fd1, EV_TIMEOUT|EV_READ|EV_PERSIST, cb_func,(char*)"Reading event");
ev2 = event_new(base, fd2, EV_WRITE|EV_PERSIST, cb_func,(char*)"Writing event");
/* 注册事件 */
event_add(ev1, &five_seconds);
event_add(ev2, NULL);
/* 循环监听 */
event_base_dispatch(base);
}
查找正在运行的事件
struct event *event_base_get_running_event(struct event_base *base);
设置事件执行一次
该函数和`event_base`类似,但是不支持`EV_SIGNAL or EV_PERSIST`。
int event_base_once(struct event_base *, evutil_socket_t, short,void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);
激活事件
如果想自己激活某个事件,那么可以执行下面的函数:
void event_active(struct event *ev, int what, short ncalls);
/*
* 参数ev为要激活的事件
* what可以为EV_READ, EV_WRITE, and EV_TIMEOUT
* ncalls为激活次数
*/
其他函数
#define evtimer_new(base, callback, arg) \
event_new((base), -, , (callback), (arg))
#define evtimer_add(ev, tv) \
event_add((ev),(tv))
#define evtimer_del(ev) \
event_del(ev)
#define evtimer_pending(ev, tv_out) \
event_pending((ev), EV_TIMEOUT, (tv_out))
循环监听
打开event loop
//@param: flags
//等待IO事件
#define EVLOOP_ONCE 0x01
//非阻塞,直接返回
#define EVLOOP_NONBLOCK 0x02
//其他的线程中添加事件
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04 int event_base_loop(struct event_base *base, int flags);
`event_loop`会检查所有IO复用方法的状态,一旦启动就会激活并使用这些IO复用方法。
如果不使用flag,可以条用下面这个函数,功能等同于`event_base_loop`,调用该函数会一直阻塞在这里,等待时间的触发。
int event_base_dispatch(struct event_base *base);
关闭event loop
//延迟tv时间后,停止event loop
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
//立刻停止,等同于tv = NULL
int event_base_loopbreak(struct event_base *base); //获取退出方式
int event_base_got_exit(struct event_base *base);
int event_base_got_break(struct event_base *base);
debug
这个函数可以把`event_base`中信息和状态写入文件中。
void event_base_dump_events(struct event_base *base, FILE *f);
例子
#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#endif
#include <time.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h> #include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h> struct timeval lasttime; int event_is_persistenet; static void
timeout_cb(evutil_socket_t fd, short event, void *arg)
{
struct timeval newtime, difference;
struct event *timeout = arg;
double elapsed; evutil_gettimeofday(&newtime, NULL);
evutil_timersub(&newtime, &lasttime, &difference);
elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6); printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
(int)newtime.tv_sec, elapsed);
lasttime = newtime; if (! event_is_persistent) {
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = ;
event_add(timeout, &tv);
}
} int main(int argc, char **argv)
{
struct event timeout;
struct timeval tv;
struct event_base *base;
int flags; if (argc == && !strcmp(argv[], "-p")) {
event_is_persistent = ;
flags = EV_PERSIST;
} else {
event_is_persistent = ;
flags = ;
} /* Initalize the event library */
base = event_base_new(); /* Initalize one event */
event_assign(&timeout, base, -, flags, timeout_cb, (void*)&timeout); evutil_timerclear(&tv);
tv.tv_sec = ;
event_add(&timeout, &tv); evutil_gettimeofday(&lasttime, NULL); event_base_dispatch(base); return ();
}
libevent (三) 事件注册与循环监听的更多相关文章
- SpringBoot | 第三十二章:事件的发布和监听
前言 今天去官网查看spring boot资料时,在特性中看见了系统的事件及监听章节.想想,spring的事件应该是在3.x版本就发布的功能了,并越来越完善,其为bean和bean之间的消息通信提供了 ...
- js事件监听器用法实例详解-注册与注销监听封装
本文实例讲述了js事件监听器用法.分享给大家供大家参考.具体分析如下: 1.当同一个对象使用.onclick的写法触发多个方法的时候,后一个方法会把前一个方法覆盖掉,也就是说,在对象的onclick事 ...
- jQuery封装自定义事件--valuechange(动态的监听input,textarea)之前值,之后值的变化
jQuery封装自定义事件--valuechange(动态的监听input,textarea)之前值,之后值的变化 js监听输入框值的即时变化 网上有很多关于 onpropertychange.oni ...
- oracle 11g在安装过程中出现监听程序未启动或数据库服务未注册到该监听程序
15511477451 原文 oracle 11g在安装过程中出现监听程序未启动或数据库服务未注册到该监听程序? 环境:win7 64位系统.oracle11g数据库 问题描述:在win7 64位系统 ...
- oracle server配置:监听程序未启动或数据库服务未注册到该监听程序
第一次安装oracle时,时完全没有任何问题的, 但是当我去配置oracle_home时,误按之下进入了Database Configuration Assistant, 然后配置已有的一个数据库,就 ...
- 监听程序未启动或数据库服务未注册到该监听程序。启动该监听程序并注册数据库服务 然后重新运行 em configuration assistant。
在WIN 7/64Bit上安装ORACLE 11gR2后,管理网页Database Control(如:https://localhost:1158/em)始终登录不进去,总是说密码错误,使用配置工具 ...
- 【京东个人中心】——Nodejs/Ajax/HTML5/Mysql爬坑之注册与登录监听
一.引言 在数据库和静态页面都创建好之后,下面就该接着完成后台Node.js监听注册和登录的部分了.这个部分主要使用的技术是:Node.js的Express框架和ajax异步请求.登录和注册的代码实现 ...
- Android初级教程使用服务注册广播接收者监听手机解锁屏变化
之前第七章广播与服务理论篇写到: 特殊的广播接收者(一般发广播次数频率很高) 安卓中有一些广播接收者,必须使用代码注册,清单文件注册是无效的 屏幕锁屏和解锁 电量改变 今天在这里就回顾一下,且用代码方 ...
- android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人
要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上 ...
随机推荐
- dubbo properties
DUBBO配置项的优先级: java -D优先于 Spring配置,Spring配置优先于 properties文件的配置,这也符合一般项目的规则. 覆盖策略: JVM启动-D参数优先,这样可以使用户 ...
- 平行四边形TikZ作图
%!TEX program = pdflatex \documentclass[varwidth=true, border=2pt]{standalone} \usepackage{tikz} \us ...
- laravel 数据库迁移
问题:之前有创建迁移文件 并且执行过 如果删除迁移文件 再重新创建迁移文件时就有问题 提示找不到之前的迁移文件 /** 一开始执行的命令 php artisan make:migration crea ...
- 使用JNDI或JDBC连接数据库
一. JNDI 1. tomcat环境 找到X:\xxx\......\apache-tomcat-6.0.39\conf\server.xml,在<Host>节点中配置如下: <H ...
- 1032 - A-B 组合数学
http://www.ifrog.cc/acm/problem/1032 1032 - A-B Time Limit:1s Memory Limit:128MByte Submissions:680S ...
- 在Linux终端命令行下播放音乐的命令(Ubuntu)
现在的 Linux 桌面已经发展的很好了,在桌面下播放音乐操作起来也很简单.那么我们还记得在桌面不是那么好的时候我们是怎么播放音乐的么?哎,我是想不起来了,实在是太难了. 不过现在我们可以先安装一个小 ...
- HTML5和CSS3基础教程(第8版)-读书笔记(3)
第11章 用CSS 进行布局 网站设计主要有两大类型:固定宽度和响应式. 对于固定(fixed)布局,整个页面和每一栏都有基于像素的宽度.顾名思义,无论是使用移动电话和平板电脑等较小的设备查看页面,还 ...
- 启用 mvc webapi 的 session功能可用
默认 mvc webapi 不开启 session 会话支持 所以需要修改配置,在 Global 开启 session 支持 如下: 1.重写 init() 方法 public override vo ...
- CentOS 6.3 安装 phpmyadmin
安装phpMyAdminphpMyAdmin是一个网络接口,通过它可以管理你的MySQL数据库.首先,我们使CentOS系统RPMForge软件库的phpMyAdmin,而不是官方的CentOS 6. ...
- 使用 IntraWeb (45) - 活用 IntraWeb
asp.net 刚开始时, 也是拖拉控件, 但后来有了 MVC.xNext. 换个思路使用 IntraWeb 吧: 界面全部用 html+js+css 实现(有些会是用 Delphi 动态生成), 然 ...