Libevent初探
检查Libevent支持的IO复用方法
int main(int argc, char **argv) {// 版本信息cout << event_get_version() << endl;// 所支持的IO复用方法const char **methods = event_get_supported_methods();for (int i = 0; methods[i] != NULL; i++) {cout << methods[i] << endl;}return 0; }
输出结果为:(Centos7 Clion 2016.1.3环境)
event_get_supported_methods()函数返回Libevent支持的IO复用方法名称数组,以NULL结尾。该函数实际返回的是全局变量eventops数组,eventops数组存放的是所有支持的IO复用函数,eventops声明部分的代码如下:
/* Array of backends in order of preference. */ /* Libevent通过遍历eventops数组来选择其后端IO复用技术,遍历的顺序是从数组的第一个元素开始,* 到最后一个元素结束。Linux系统下,默认选择的后端IO复用技术是epoll。*/ static const struct eventop *eventops[] = { #ifdef _EVENT_HAVE_EVENT_PORTS&evportops, #endif #ifdef _EVENT_HAVE_WORKING_KQUEUE&kqops, #endif #ifdef _EVENT_HAVE_EPOLL&epollops, #endif #ifdef _EVENT_HAVE_DEVPOLL&devpollops, #endif #ifdef _EVENT_HAVE_POLL&pollops, #endif #ifdef _EVENT_HAVE_SELECT&selectops, #endif #ifdef WIN32&win32ops, #endifNULL };
Libevent是如何打日志的
void log(const char *fmt, ...) {char buff[512];va_list ap;va_start(ap, fmt);int len = vsnprintf(buff, sizeof(buff), fmt, ap);buff[len] = '\0';va_end(ap);cout << buff << endl; }
- va_start:宏定义,引用最后一个固定参数所以它能够对可变参数进行定位。
- va_end:宏定义,函数返回之前一定要调用va_end,这是因为某些实现在函数返回之前需要调整控制信息。
log("hi, are you %s?", "luxon28"); log("name=%s, age=%d", "luoxn28", 23);
更多va_start/va_end信息请点击:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html。
定时器的使用
#include <iostream>#include <event.h> #include <event2/http.h>using namespace std;// Time callback function void onTime(int sock, short event, void *arg) {static int cnt = 0;cout << "Game Over! " << cnt++ << endl;struct timeval tv;tv.tv_sec = 1;tv.tv_usec = 0;if (cnt < 5) {// Add timer eventevent_add((struct event *) arg, &tv);}else {cout << "onTime is over" << endl;} }int main(int argc, char **argv) {cout << event_get_version() << endl;struct event_base *base = event_init();struct event ev;evtimer_set(&ev, onTime, &ev);struct timeval timeevent;timeevent.tv_sec = 1;timeevent.tv_usec = 0;event_add(&ev, &timeevent);// Start event loopevent_base_dispatch(base);event_base_free(base);return 0; }
输出结果如下:
LZ安装的是Libevent版本是2.0版本,event_init()函数初始化一个事件类结构体,其中已经选择好了IO复用函数,比如Linux下一般是epoll;初始化了一个事件活动队列,当事件发生时,会被加入到该事件活动队列中,然后统一执行事件活动队列中的所有事件(也就是调用对应的回调函数)。event_base结构体详细内容如下:
/* 结构体event_base是Libevent的Reactor */ struct event_base {/* 初始化Reactor时选择的一种后端IO复用机制,并记录在如下字段中 */const struct eventop *evsel;/* 指向IO复用机制真正存储的数据,它通过evsel成员的init函数来进行初始化 */void *evbase;/* 事件变化队列,其用途是:如果一个文件描述符上注册的事件被多次修改,则可以使用缓冲区来避免重复的* 系统调用(比如epoll_wait)。它仅能用于时间复杂度为O(1)的IO复用技术 */struct event_changelist changelist;/* 指向信号的后端处理机制,目前仅在singal.h文件中定义了一种处理方法 */const struct eventop *evsigsel;/* 信号事件处理器使用的数据结构,其中封装了一个由socketpair创建的管道。它用于信号处理函数和* 事件多路分发器之间的通信 */struct evsig_info sig;/* 以下3个成员是添加到该event_base的虚拟事件、所有事件和激活事件的数量 */int virtual_event_count;int event_count;int event_count_active;/* 是否执行完活动事件队列上的剩余的任务之后就退出事件处理 */int event_gotterm;/* 是否立即退出事件循环,而不管是否还有任务需要处理 */int event_break;/* 是否应该启动一个新的事件循环 */int event_continue;/* 目前正在处理的活动事件队列的优先级 */int event_running_priority;/* 事件循环是否启动 */int running_loop;/* 活动事件队列数组,索引值越小的队列,优先级越高。高优先级的活动事件队列中的事件处理器将被优先处理 */struct event_list *activequeues;/* 活动事件队列数组的大小,即该event_base共有nactivequeues个不同优先级的活动事件队列 */int nactivequeues;/* common timeout logic *//* 以下3个成员用于管理通用定时器队列 */struct common_timeout_list **common_timeout_queues;int n_common_timeouts;int n_common_timeouts_allocated;/* 存放延时回调函数的链表,事件循环每次成功处理完一个活动事件队列中的所有事件之后,* 就调用一次延迟回调函数 */struct deferred_cb_queue defer_queue;/* 文件描述符和IO事件之间的映射关系表 */struct event_io_map io;/* 信号值和信号事件之间的映射关系表 */struct event_signal_map sigmap;/* 注册事件队列,存放IO事件处理器和信号事件处理器 */struct event_list eventqueue;struct timeval event_tv;/* 时间堆 */struct min_heap timeheap;struct timeval tv_cache;#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)/** Difference between internal time (maybe from clock_gettime) and* gettimeofday. */struct timeval tv_clock_diff;/** Second in which we last updated tv_clock_diff, in monotonic time. */time_t last_updated_clock_diff; #endif/* 多线程支持 */ #ifndef _EVENT_DISABLE_THREAD_SUPPORT/* threading support *//** The thread currently running the event_loop for this base *//* 当前运行该event_base的事件循环的线程 */unsigned long th_owner_id;/** A lock to prevent conflicting accesses to this event_base */void *th_base_lock; /* 锁变量 *//** The event whose callback is executing right now *//* 当前事件循环正在执行哪个事件处理器的回调函数 */struct event *current_event;/** A condition that gets signalled when we're done processing an* event with waiters on it. *//* 条件变量,用于唤醒正在等待某个事件处理完毕的线程 */void *current_event_cond;/** Number of threads blocking on current_event_cond. */int current_event_waiters; /* 等待current_event_cond的线程数 */ #endif/** Flags that this base was configured with *//* 该vent_base的一些配置参数 */enum event_base_config_flag flags;/* 下面这些成员变量给工作线程唤醒主线程提供了方法(使用socketpair创建的管道) *//* Notify main thread to wake up break, etc. *//** True if the base already has a pending notify, and we don't need* to add any more. */int is_notify_pending;/** A socketpair used by some th_notify functions to wake up the main* thread. */evutil_socket_t th_notify_fd[2];/** An event used by some th_notify functions to wake up the main* thread. */struct event th_notify;/** A function used to wake up the main thread from another thread. */int (*th_notify_fn)(struct event_base *base); }
event_add()函数是往事件结构体中加入监听的一个事件,这里是定时事件,当定时事件到时,就会执行对应的回调函数。event_base_dispatch()函数开始执行事件监听,对应于epoll的话也就是调用epoll_wait了。最后,当程序执行完毕后,需要调用event_base_free()函数来执行资源的销毁操作,至此,整个定时器事件就执行完毕了。
简单的HTTP服务器
使用Libevent,我们可以用不超过50行代码实现一个简单的HTTP服务器程序,没有听错,就是几十行代码,不像Java那样,需要配置Tomcat,然后编写对应的Servet,配置web.xml等等(如果使用SSM或者SSH的话步骤或许更多一点呦 :( )。下面就是一个简单的HTTP服务器示例代码:
#include <iostream>#include <event2/event.h> #include <event2/buffer.h> #include <event2/http.h>using namespace std;#define INFO 1 #define ERR 3 static void log(int level, string info) {switch (level) {case INFO:cout << "[info] tid[" << pthread_self() << "]: " << info << endl;break;case ERR:cout << "[err] tid[" << pthread_self() << "]: " << info << endl;break;default:break;} }/*** http callback function*/ void httpHandler(struct evhttp_request *request, void *arg) {struct evbuffer *buff = evbuffer_new();if (!buff) {log(INFO, "evbuffer_new error");return;}evbuffer_add_printf(buff, "Hello world</br>");evbuffer_add_printf(buff, "Server Responsed.</br> Requested: %s<br/>", evhttp_request_get_uri(request));evbuffer_add_printf(buff, " Host: %s<br/>", evhttp_request_get_host(request));evbuffer_add_printf(buff, " Command: %d", evhttp_request_get_command(request));evhttp_send_reply(request, HTTP_OK, "OK", buff);evbuffer_free(buff); }int main(int argc, char **argv) {struct event_base *base = event_base_new();struct evhttp *httpServer = evhttp_new(base);int result = evhttp_bind_socket(httpServer, NULL, 8080);if (result != 0) {log(ERR, "evhttp_bind_socket error");return -1;}/* 这是http回调函数 */evhttp_set_gencb(httpServer, httpHandler, NULL);cout << "Http server start OK..." << endl;event_base_dispatch(base);evhttp_free(httpServer);event_base_free(base);return 0; }
访问页面如下,192.168.1.150主机是linux服务器。
看到这里,学习Java Web的小伙伴是不是觉得很熟悉,没错,就是像Servlet。LZ个人觉得,对于小型程序来说,使用C/C++的网络库编程程序更爽一点,因为更加"接地气 "一点,也就操作起来更加灵活,使用Java的话肯定要使用Servet容器了,比如Tomcat或者Jboss等,然后各种配置等。但是对于动态Web技术来说,使用Java更爽一点。
转载于:https://www.cnblogs.com/luoxn28/p/5813860.html
Libevent初探相关推荐
- 利用epoll写一个迷你的网络事件库
epoll是linux下高性能的IO复用技术,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率.另一点原因就是获取 ...
- php实现epoll,PHP socket初探 --- 颤颤抖抖开篇libevent(一)
正如标题所言,颤颤抖抖开篇epoll.颤颤抖抖的原因大概也就是以前几乎没有亲自"手刃"epoll的经验,仅仅靠epoll的理论知识骗吃骗喝骗人事哄小孩儿装高手,现如今,没有了大师兄 ...
- php libevent 问题,PHP Socket 初探 —— 硬着头皮继续 libevent(二)
libevent中有五个字母是event,实际上就是说"event才是王道". Event类就是产生各种不同类型事件的产出器,比如定时器事件.读写事件等等,为了提升民族荣誉感,我们 ...
- Memcached初探
2019独角兽企业重金招聘Python工程师标准>>> 初探的意思就是装起来玩儿一把,最简单的,所以这里写的东西不一定对,小心! 1. install 2. simple clien ...
- 2021年大数据Flink(九):Flink原理初探
Flink原理初探 Flink角色分工 在实际生产中,Flink 都是以集群在运行,在运行的过程中包含了两类进程. JobManager: 它扮演的是集群管理者的角色,负责调度任务.协调 checkp ...
- 从壹开始微服务 [ DDD ] 之一 ║ D3模式设计初探 与 我的计划书
缘起 哈喽大家周四好!又是开心的一天,时间过的真快,我们的 <从壹开始 .net core 2.1 + vue 2.5 >前后端分离系列共 34 篇已经完结了,当然以后肯定还会有更新和修改 ...
- 经典算法研究系列:二、Dijkstra 算法初探
经典算法研究系列:二.Dijkstra 算法初探 July 二零一一年一月 ====================== 本文主要参考:算法导论 第二版.维基百科. 写的不好之处,还望见谅. 本 ...
- 使用libevent多线程验证Linux上的服务器惊群现象
什么是惊群现象? 惊群(thundering herd)是指,只有一个子进程能获得连接,但所有N个子进程却都被唤醒了,这种情况将使性能受损. 举一个很简单的例子,当你往一群鸽子中间扔一块食物,虽然最终 ...
- Linux下的Memcache安装(含libevent的安装)
Linux下Memcache服务器端的安装 服务器端主要是安装memcache服务器端,目前的最新版本是 memcached-1.3.0 . 下载:http://www.danga.com/memca ...
最新文章
- 双12众商超沦陷,你是否习惯了扮演观众?
- 这个网盘搜索好像还不错
- html5/css3响应式布局介绍及设计流程
- 2020CCPC长春
- 欧盟无条件批准甲骨文收购Sun
- Go语言之进阶篇http服务器获取客户端的一些信息
- eclipse中的插件安装(svn、maven、jetty等)
- 并发编程(读书笔记)
- 个人使用mysql_MySql使用总结
- 第五章 shell学习之文件的排序、合并和分割
- react月份选择控件_一款很实用的ReactJS日期范围选择控件
- 设计模式--代理模式Proxy(结构型)
- 2018年程序员书单
- windows如何设置软件开机启动
- Openbravo开发手册
- 腾讯词向量下载链接(Tencent_AILab_ChineseEmbedding.txt)
- 联想拯救者y7000p2022款 配置
- PCB设计1 模块间的隔离
- Java default关键字与protect的区别之处
- 遇到问题 SCO UNIX 不能TELNET 本机
热门文章
- 【牛客 - 696C】小w的禁忌与小G的长诗(dp 或 推公式容斥)
- 【CH - 1401】 兔子与兔子(字符串哈希)
- 【CodeForces - 1038C】Gambling (博弈问题,优先队列模拟,贪心)
- 14.深度学习练习:Face Recognition for the Happy House
- csv转为utf8编码_读取UTF8编码的CSV并转换为UTF-16
- 计算机英语反思总结,计算机在英语教学中辅助作用的反思
- 计算机专业的三行情书,各专业三行情书,看懂你就是全能学霸!
- 13个mysql数据库的实用SQL小技巧
- 二叉树相关知识及求深度的代码实现
- leetcode27 移除元素