【帮助】辅助类型和兼容函数


<event2/util.h>定义了很多在实现可移植应用时有用的函数,libevent内部也使用这些类型和函数。

基本类型
1、evutil_socket_t

在除Windows之外的大多数地方,套接字是个整数,操作系统按照数值次序进行处理。然而,使用Windows套接字API时,socket具有类型SOCKET,它实际上是个类似指针的句柄,收到这个句柄的次序是未定义的。在Windows中,libevent定义evutil_socket_t类型为整型指针,可以处理socket()或者accept()的输出,而没有指针截断的风险

定义:

#ifdef WIN32                                        
#define evutil_socket_t intptr_t                                        
#else                                        
#define evutil_socket_t int                                        
#endif


定时器可移植函数

不是每个平台都定义了标准timeval操作函数,所以libevent也提供了自己的实现

接口:

//分别对前两个参数进行加或者减运算,将结果存放到第三个参数中
#define evutil_timeradd(tvp, uvp, vvp) /* ...*/
#define evutil_timersub(tvp, uvp, vvp) /* ...*/

接口:

//清除 timeval会将其值设置为0。
#define evutil_timerclear(tvp) /* ...*/

//判断timeval是否为0;如果是0则返回false,否则返回true
#define evutil_timerisset(tvp) /* ...*/

接口:

//比较两个timeval
//这样使用:
//evutil_timercmp(t1,t2,<=)含义为:判断"t1<=t2”是否成立
//如果其关系满足cmp关系运算符,返回true
//cmp为所有C关系运算符(也就是<、>、==、!=、<=和>=)
#define evutil_timercmp(tvp, uvp, cmp)

接口:

//获取当前时间并保存到tv;
//tz目前无用
int evutil_gettimeofday(struct timeval* tv, struct timezone * tz);

套接字API兼容性
1、关闭套接字

接口:

#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)

//在使用该函数之前,需要定义上面的那个宏
int evutil_closesocket(evutil_socket_t s);

在Unix中,它是close()的别名;在Windows中,它调用closesocket()。
在Windows中不能将close()用于套接字,也没有其他系统定义了closesocket()

这些宏访问和操作套接字错误代码。

含义
#define EVUTIL_SOCKET_ERROR()返回当前线程最后一次套接字操作的全局错误号
#define EVUTIL_SET_SOCKET_ERROR(errcode)修改当前套接字的错误号(与设置Unix中的errno类似)
#define evutil_socket_geterror(sock)返回特定的套接字的错误号 (在类 Unix系统中都是errno)
#define evutil_socket_error_to_string(errcode)返回代表某给定套接字错误号的字符串(与Unix中的strerror()类似)

因为对于来自套接字函数的错误, Windows不使用errno,而是使用WSAGetLastError() ,所以需要这些函数。
注意:Windows套接字错误与从errno看到的标准C错误是不同的。


2、设置socket为非阻塞状态

接口:

int evutil_make_socket_nonblocking(evutil_socket_t sock);

用于对套接字进行非阻塞IO的调用也不能移植到Windows中。
该函数要求一个套接字【来自socket()或accept()函数】作为参数,将其设置为非阻塞的。


3、设置套接字地址可重用

接口:

int evutil_make_listen_socket_reuseable(evutil_socket_t sock);

确保关闭监听套接字后,它使用的地址可以立即被另一个套接字使用。
多个套接字绑定到相同地址

(在Unix中它设置SO_REUSEADDR标志,在Windows中则不做任何操作。不能在Windows中使用SO_REUSEADDR标志,它有另外不同的含义)


可移植的字符串操作函数

接口:

int evutil_snprintf(char* buf, size_t buflen, const char * format, ...);
int evutil_vsnprintf(char* buf, size_t buflen, const char * format, va_list ap);

这些snprintf替代函数的行为与标准snprintf和vsnprintf接口相同。
函数返回在缓冲区足够长的情况下将写入的字节数,不包括结尾的NULL字节。(这个行为遵循C99的snprintf()标准,但与Windows的_snprintf()相反:如果字符串无法放入缓冲区,_snprintf()会返回负数)


安全随机数发生器

接口:

void evutil_secure_rng_get_bytes(void* buf, size_t n);

这个函数用随机数据填充buf处的n个字节。


日志配置

Libevent能记录内部的错误和警告日志,如果编译进日志支持功能,也会记录调试信息。默认情况下这些消息都是输出到stderr,你也可以通过提供自己的日志函数的方法来覆盖这种行为。

接口:

#define EVENT_LOG_DEBUG 0
#define EVENT_LOG_MSG 1
#define EVENT_LOG_WARN 2
#define EVENT_LOG_ERR 3

/* Deprecated; see note at the end of this section*/
#define _EVENT_LOG_DEBUG    EVENT_LOG_DEBUG
#define _EVENT_LOG_MSG        EVENT_LOG_MSG
#define _EVENT_LOG_WARN     EVENT_LOG_WARN
#define _EVENT_LOG_ERR          EVENT_LOG_ERR
 
typedef void ( * event_log_cb)(int severity, const char* msg);
 
void event_set_log_callback(event_log_cb cb);

为了覆盖Libevent的日志行为,你需要自己编写满足event_log_cb格式的函数,然后将函数作为参数传入event_set_log_callback()。
无论什么时候只要Libevent需要写一个日志,都会进入到你提供的日志函数。

再次调用event_set_log_callback()并传一个NULL,可让日志功能再次回到默认功能。

例子:

#include <event2/event.h>
#include <stdio.h>
static void discard_cb(int severity, const char* msg)
{
	/* This callback does nothing.*/
}
static FILE* logfile = NULL;
static void write_to_file_cb(int severity, const char* msg)
{
	const char* s;
	if (!logfile)
		return;
	switch (severity) 
	{
		case _EVENT_LOG_DEBUG: s = "debug"; break;
		case _EVENT_LOG_MSG: s = "msg"; break;
		case _EVENT_LOG_WARN: s = "warn"; break;
		case _EVENT_LOG_ERR: s = "error"; break;
		default: s = "?"; break; /* never reached*/
	}
	fprintf(logfile, "[%s] %s\n", s, msg);
}
/* Turn off all logging from Libevent.*/
void suppress_logging(void)
{
	event_set_log_callback(discard_cb);
}
/* Redirect all Libevent log messages to the C stdio file ‘f’.*/
void set_logfile(FILE* f)
{
	logfile = f;
	event_set_log_callback(write_to_file_cb);
}

注意:在用户提供的event_log_cb回调函数中进行Libevent的函数调用是不安全的。如果你想写一个用bufferevents去发送告警信息给一个网络socket的日志回调函数,你就可能会遇到非常奇怪和难以诊断的错误。

通常调试日志都是禁用的,也都不会发送给日志回调函数,但是如果libevent是编译成支持打开调试日志,你就可以手动打开调试日志。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值