(1)libevent 创建event_base
创建event_base
1、创建默认的event_base, 从全局变量eventops中选出操作系统支持的最快方法 。它直接调用event_base_new_with_config。
struct event_base *event_init(void);
struct event_base *event_base_new(void);
void event_base_free(struct event_base *);
2、创建复杂event_base
2.1 分配一个 event_config。
struct event_config * pConfig = event_config_new();
void event_config_free(struct event_config *cfg);
2.2 创建base时,选择支持指定的I/O复用机制。
int event_config_require_features(struct event_config *cfg, int feature);
enum event_base_config_flag {
/** 不要为 event_base分配锁.设置这个选项可以为event_base节省一点用于锁定和解锁的时
间,但是让在多个线程中访问 event_base成为不安全的.*/
EVENT_BASE_FLAG_NOLOCK = 0x01,
/** 选择使用的后端时,不要检测EVENT_*环境变量 */
EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
/** 仅用于 Windows,让 libevent在启动时就启用任何必需的IOCP分发逻辑,而不是按需启用.*/
EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
/** 不是在每次事件循环准备好运行超时回调时检查当前时间,而是在每次超时回调之后检查。*/
EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
/** 告诉 base,如果决定使用epoll后端,可以安全地使用更快的基于 changelist的后端.
epoll-changelist后端可以在后端的分发函数调用之间,同样的fd多次修改其状态的情况下,避免不必要的系统调用.
但是如果传递任何使用 dup ()或者其变体克隆的 fd给libevent, epoll-changelist后端会触发一个内核bug,
导致不正确的结果.在不使用epoll后端的情况下,这个标志是没有效果的.
也可以通过设置 EVENT_EPOLL_USE_CHANGELIST:环境变量来打开epoll-changelist选项.*/
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
/** 通常,Libevent使用我们所拥有的最快的单调计时器来实现它的时间和超时代码。
但是,如果设置了这个标志,我们将使用效率较低的更精确的计时器(假设存在计时器)。*/
EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
2.3 使用 event_config_set_flag 函数设置支持指定特性的I/O复用机制。
/* 通过flag设置base的某些参数特征,flag的枚举值见event_base_config_flag*/
int event_config_set_flag(struct event_config *cfg, int flag);
enum event_base_config_flag {
/** 不要为 event_base分配锁.设置这个选项可以为event_base节省一点用于锁定和解锁的时
间,但是让在多个线程中访问 event_base成为不安全的.*/
EVENT_BASE_FLAG_NOLOCK = 0x01,
/** 选择使用的后端时,不要检测EVENT_*环境变量 */
EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
/** 仅用于 Windows,让 libevent在启动时就启用任何必需的IOCP分发逻辑,而不是按需启用.*/
EVENT_BASE_FLAG_STARTUP_IOCP = 0x04,
/** 不是在每次事件循环准备好运行超时回调时检查当前时间,而是在每次超时回调之后检查。*/
EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
/** 告诉 base,如果决定使用epoll后端,可以安全地使用更快的基于 changelist的后端.epoll-changelist后端可以在后端的分发函数调用之间,同样的fd多次修改其状态的情况下,避免不必要的系统调用.但是如果传递任何使用 dup ()或者其变体克隆的 fd给libevent, epoll-changelist后端会触发一个内核bug,导致不正确的结果.在不使用epoll后端的情况下,这个标志是没有效果的.也可以通过设置 EVENT_EPOLL_USE_CHANGELIST:环境变量来打开epoll-changelist选项.*/
EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
/** 通常,Libevent使用我们所拥有的最快的单调计时器来实现它的时间和超时代码。但是,如果设置了这个标志,我们将使用效率较低的更精确的计时器(假设存在计时器)。*/
EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
2.4 通过 event_config_avoid_method 函数使用字符串的方式指定base不使用指定的I/O复用机制
int event_config_avoid_method(struct event_config *cfg, const char *method);
// 指定不使用select机制
event_config_avoid_method(cfg, "select");
2.5 通过 event_get_supported_methods 函数获取所有的支持的I/O复用机制
// 获取系统所有支持的I/O复用机制
const char **event_get_supported_methods(void);
// 获取base支持的I/O复用机制。
const char *event_base_get_method(const struct event_base *);
2.6 通过 event_config 初始化一个 event_base
struct event_base *event_base_new_with_config(const struct event_config *);
2.7 使用 event_base_get_features 获取event_base的 event_config的配置,用于检验配置是否生效
int event_base_get_features(const struct event_base *base);
2.8 使用 event_base_priority_init 设置 event_base 优先级别
/**n_priorities 是要支持的优先级数目,这个数目至少是 1,优先级将从 0 (最高) 到 n_priorities-1(最低)
必须在任何事件激活之前调用这个函数,最好在创建 event_base 后立刻调用。
*/
int event_base_priority_init(struct event_base *base, int n_priorities);
#define EVENT_MAX_PRIORITIES 256
2.9 使用 event_reinit 重新初始化 event_base
/**不是所有事件都在调用 fork()之后可以正确工作。所以,如果在使用 fork()或者其他相关系统调用启动新进程之后,
希望在新进程中继续使用 event_base,就需要进行重新初始化。
*/
int event_reinit(struct event_base *base);
3.0 其他函数使用
// 初始化event的线程
evthread_use_windows_threads();
// 设置系统CPU数量
SYSTEM_INFO info;
GetSystemInfo(&info);
event_config_set_num_cpus_hint(pConfig, info.dwNumberOfProcessors/*进程数量*/);
一、遍历系统支持那些网络模型
#include <iostream>
#include <event2/event.h>
#include <event2/listener.h>
#ifndef _WIN32
#include <signal.h>
#include <string.h>
#endif
using namespace std;
#define SPORT 5001
int main()
{
#ifdef _WIN32
WSADATA was;
WSAStartup(MAKEWORD(2, 2), &was);
#else
// 忽略管道信号,发送数据给已关闭的socket,程序会崩溃
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
// 创建配置上下文
event_config * pConfig = event_config_new();
// 显示支持的网络模式
const char ** methods = event_get_supported_methods();
for (int i = 0; methods[i] != NULL; i++)
{
std::cout << i << " " << methods[i] << std::endl;
}
// 设置支持哪些特征
//设置了EV_FEATURE_FDS 其他特征就无法设置,在windows中EV_FEATURE_FDS无效
//event_config_require_features(conf, EV_FEATURE_ET| EV_FEATURE_FDS);
event_config_require_features(pConfig, EV_FEATURE_ET);
// 根据配置项生成上下文
event_base *pBase = event_base_new_with_config(pConfig);
event_config_free(pConfig); // 使用完后可释放。
if (!pBase)
{
pBase = event_base_new(); //取默认配置
if (!pBase)
return 0;
}
else
{
//确认特征是否生效
int f = event_base_get_features(pBase);
if (f&EV_FEATURE_ET)// 边沿触发
cout << "EV_FEATURE_ET events are supported." << endl;
else
cout << "EV_FEATURE_ET events are not supported." << endl;
if (f&EV_FEATURE_O1)// 操作是0 (1)复杂度的后端
cout << "EV_FEATURE_O1 events are supported." << endl;
else
cout << "EV_FEATURE_O1 events are not supported." << endl;
if (f&EV_FEATURE_FDS)// 要求支持任意文件描述符,此网络模型不支持epoll,而不仅仅是套接字的后端
cout << "EV_FEATURE_FDS events are supported." << endl;
else
cout << "EV_FEATURE_FDS events are not supported." << endl;
if (f&EV_FEATURE_EARLY_CLOSE)// 检测连接关闭事件
cout << "EV_FEATURE_EARLY_CLOSE events are supported." << endl;
else
cout << "EV_FEATURE_EARLY_CLOSE events are not supported." << endl;
cout << "event_base_new_with_config success!" << endl;
event_base_free(pBase);
}
event_base_free(pBase);
#ifdef _WIN32
WSACleanup();
#endif //
return 0;
}
二、支持windows的iocp模型示例
void listen_cb(struct evconnlistener * e, evutil_socket_t s,
struct sockaddr * a, int socklen, void *arg)
{
std::cout << "listen_cb" << std::endl;
}
int main()
{
#ifdef _WIN32
WSADATA was;
WSAStartup(MAKEWORD(2, 2), &was);
#else
// 忽略管道信号,发送数据给已关闭的socket
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
// 创建配置上下文
event_config * pConfig = event_config_new();
#ifdef _WIN32
// windows中设置支持iocp(线程池)
event_config_set_flag(pConfig, EVENT_BASE_FLAG_STARTUP_IOCP);
// 初始化iocp的线程
evthread_use_windows_threads();
// 设置系统CPU数量
SYSTEM_INFO info;
GetSystemInfo(&info);
event_config_set_num_cpus_hint(pConfig, info.dwNumberOfProcessors/*进程数量*/);
#endif // _WIN32
//初始化配置libevent上下文
event_base *base = event_base_new_with_config(pConfig);
event_config_free(pConfig);
if (!base)
{
base = event_base_new();
if (!base)
return 0;
}
else
{
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SPORT);
evconnlistener * ev = evconnlistener_new_bind(base, listen_cb, base, 10,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
(sockaddr*)&sin, sizeof(sin));
event_base_dispatch(base);
evconnlistener_free(ev);
event_base_free(base);
}
#ifdef _WIN32
WSACleanup();
#endif //
return 0;
}
分类:
16、libevent框架
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
2018-11-08 linux::jsoncpp库