(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;
}
posted @   osbreak  阅读(29)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示