LibEvent中文帮助文档--第9章【辅助类型和函数】

来源:互联网 发布:xp linux双系统安装 编辑:程序博客网 时间:2024/05/17 04:31




LibEvent中文帮助文档--第9章【辅助类型和函数】


   返回主目录


Libevent


快速可移植非阻塞式网络编程

 

 

修订历史

版本

日期

作者

备注

V1.0

2016-11-15

周勇

Libevent编程中文帮助文档

 

文档是2009-2012年由Nick-Mathewson基于Attribution-Noncommercial-Share Alike许可协议3.0创建,未来版本将会使用约束性更低的许可来创建.

此外,本文档的源代码示例也是基于BSD"3条款""修改"条款.详情请参考BSD文件全部条款.本文档最新下载地址:

英文:http://libevent.org/

中文:http://blog.csdn.net/zhouyongku/article/details/53431750

请下载并运行"gitclonegit://github.com/nmathewson/libevent- book.git"获取本文档描述的最新版本源码.



<<上一章>>


9.辅助类型和函数

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

 

9.1基本类型

9.1.1Evuitl_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


这个类型在2.0.1-alpha版本中引入.

9.1.2标准整数类型

落后于21世纪的C系统常常没有实现C99标准规定的stdint.h头文件.考虑到这种情况,libevent定义了来自于stdint.h的、位宽度确定(bit-width-specific)的整数类型:

 

Type

Width

Signed

Maximum

Minimum

ev_uint64_t

64

No

EV_UINT64_MAX

0

ev_int64_t

64

Yes

EV_INT64_MAX

EV_INT64_MIN

ev_uint32_t

32

No

EV_UINT32_MAX

0

ev_int32_t

32

Yes

EV_INT32_MAX

EV_INT32_MIN

ev_uint16_t

16

No

EV_UINT16_MAX

0

ev_int16_t

16

Yes

EV_INT16_MAX

EV_INT16_MIN

ev_uint8_t

8

No

EV_UINT8_MAX

0

ev_int8_t

8

Yes

EV_INT8_MAX

EV_INT8_MIN

 

C99标准一样,这些类型都有明确的位宽度.

 

这些类型由1.4.0-alpha版本引入.MAX/MIN常量首次出现在2.0.4-alpha版本.

9.1.3各种兼容性类型

在有 ssize_t(有符号的size_t)类型的平台上,ev_ssize_t定义为ssize_t;而在没有的平台上,则定义为某合理的默认类型.ev_ssize_t类型的最大可能值是EV_SSIZE_MAX;最小可能值是EV_SSIZE_MIN. (在平台没有定义SIZE_MAX的时候,size_t类型的最大可能值是EV_SIZE_MAX)

 

ev_off_t用于代表文件或者内存块中的偏移量.在有合理off_t类型定义的平台,它被定义为off_t;Windows上则定义为ev_int64_t.

 

某些套接字 API定义了socklen_t长度类型,有些则没有定义.在有这个类型定义的平台中,ev_socklen_t定义为socklen_t,在没有的平台上则定义为合理的默认类型.

 

ev_intptr_t是一个有符号整数类型,足够容纳指针类型而不会产生截断;ev_uintptr_t则是相应的无符号类型.

 

ev_ssize_t类型由2.0.2-alpha版本加入.ev_socklen_t类型由2.0.3-alpha版本加入.ev_intptr_tev_uintptr_t类型,以及EV_SSIZE_MAX/MIN宏定义由2.0.4-alpha版本加入.ev_off_t类型首次出现在2.0.9-rc版本.

 

9.2定时器可移植函数

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

 

接口

#define evutil_timeradd(tvp, uvp, vvp) /* ...*/#define evutil_timersub(tvp, uvp, vvp) /* ...*/

这些宏分别对前两个参数进行加或者减运算,将结果存放到第三个参数中.

 

接口

#define evutil_timerclear(tvp) /* ...*/#define evutil_timerisset(tvp) /* ...*/


清除 timeval会将其值设置为0.evutil_timerisset宏检查timeval是否已经设置,如果已经设置为非零值,返回ture,否则返回false.

 

接口

#define evutil_timercmp(tvp, uvp, cmp)

evutil_timercmp宏比较两个timeval,如果其关系满足cmp关系运算符,返回true.比如说,evutil_timercmp(t1,t2,<=)的意思是"是否t1<=t2".注意:与某些操作系统版本不同的是,libevent的时间比较支持所有C关系运算符(也就是<>==!=<=>=) .

 

接口

int evutil_gettimeofday(struct timeval* tv, struct timezone * tz);

evutil_gettimeofdy()函数设置tv为当前时间,tz参数未使用.

 

示例

struct timeval tv1, tv2, tv3;/* Set tv1 = 5.5 seconds*/tv1.tv_sec = 5; tv1.tv_usec = 500 * 1000;/* Set tv2 = now*/evutil_gettimeofday(&tv2, NULL);/* Set tv3 = 5.5 seconds in the future*/evutil_timeradd(&tv1, &tv2, &tv3);/* all 3 should print true*/if (evutil_timercmp(&tv1, &tv1, ==)) /* == "If tv1 == tv1"*/puts("5.5 sec == 5.5 sec");if (evutil_timercmp(&tv3, &tv2, >=)) /* == "If tv3 >= tv2"*/puts("The future is after the present.");if (evutil_timercmp(&tv1, &tv2, <)) /* == "If tv1 < tv2"*/puts("It is no longer the past.");


___________________________________________________________________________________________________
注意

LibEvent1.4.4之前用<=>=timercmp一起使用是不安全的.

____________________________________________________________________________________________________

9.3套接字API兼容性

本节由于历史原因而存在: Windows从来没有以良好兼容的方式实现Berkele y套接字API.

 

接口

int evutil_closesocket(evutil_socket_t s);#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)

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

 

evutil_closesocket()函 数 在2.0.5-alpha版 本 引 入.在 此 之 前,需 要 使 用EVUTIL_CLOSESOCKET.

 

接口

#define EVUTIL_SOCKET_ERROR()#define EVUTIL_SET_SOCKET_ERROR(errcode)#define evutil_socket_geterror(sock)#define evutil_socket_error_to_string(errcode)

这些宏访问和操作套接字错误代码.EVUTIL_SOCKET_ERROR()返回本线程最后一次套接字操作的全局错误号,evutil_socket_geterror()则返回某特定套接字的错误号. (在类 Unix系统中都是errno)EVUTIL_SET_SOCKET_ERROR()修改当前套接字错误号(与设置Unix中的errno类似) ,evutil_socket_error_to_string()返回代表某给定套接字错误号的字符串(Unix中的strerror()类似) .

 

(因为对于来自套接字函数的错误, Windows不使用errno,而是使用WSAGetLastError() ,

所以需要这些函数. )

 

注意:Windows套接字错误与从errno看到的标准C错误是不同的.

 

接口

int evutil_make_socket_nonblocking(evutil_socket_t sock);

IO的 调 用 也 不 能 移 植 到Windows.evutil_make_socket_nonblocking()函数要求一个套接字(来自socket()或者accept())作为参数,将其设置为非阻塞的. (设置Unix中的O_NONBLOCK标志和Windows中的FIONBIO标志)

 

接口

int evutil_make_listen_socket_reuseable(evutil_socket_t sock);

这个函数确保关闭监听套接字后,它使用的地址可以立即被另一个套接字使用. (Unix中它设置SO_REUSEADDR标志,Windows中则不做任何操作.不能在Windows中使用SO_REUSEADDR标志:它有另外不同的含义(译者注:多个套接字绑定到相同地址) )


接口

int evutil_make_socket_closeonexec(evutil_socket_t sock);


这个函数告诉操作系统,如果调用了exec(),应该关闭指定的套接字.Unix中函数设置FD_CLOEXEC标志,Windows上则没有操作.

 

接口

int evutil_socketpair(int family, int type, int protocol,evutil_socket_t sv[2]);

这个函数的行为跟 Unixsocketpair()调用相同:创建两个相互连接起来的套接字,可对其使用普通套接字IO调用.函数将两个套接字存储在sv[0]sv[1],成功时返回0,失败时返回-1.

 

Windows,这个函数仅能支持AF_INET协议族、SOCK_STREAM类型和0协议的套接字.注意:在防火墙软件明确阻止127.0.0.1,禁止主机与自身通话的情况下,函数可能失败.

 

除了 evutil_make_socket_closeonexec()2.0.4-alpha版本引入外,这些函数都由1.4.0-alpha版本引入.


9.4可移植的字符串操作函数

 

接口

ev_int64_t evutil_strtoll(const char* s, char ** endptr, int base);

这个函数与 strtol行为相同,只是用于64位整数.在某些平台上,仅支持十进制.

 

接口

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替代函数的行为与标准snprintfvsnprintf接口相同.函数返回在缓冲区足够长的情况下将写入的字节数,不包括结尾的NULL字节. (这个行为遵循C99snprintf()标准,但与Windows_snprintf()相反:如果字符串无法放入缓冲区,_snprintf()会返回负数)

 

evutil_strtoll()1.4.2-rc版本就存在了,其他函数首次出现在1.4.5版本中.

 

9.5区域无关的字符串操作函数

实现基于 ASCII的协议时,可能想要根据字符类型的ASCII记号来操作字符串,而不管当前的区域设置.libevent为此提供了一些函数:

 

接口

int evutil_ascii_strcasecmp(const char* str1, const char * str2);int evutil_ascii_strncasecmp(const char* str1, const char * str2, size_t n);

这些函数与 strcasecmp()strncasecmp()的行为类似,只是它们总是使用ASCII字符集进行比较,而不管当前的区域设置.这两个函数首次在2.0.3-alpha版本出现.

 

9.6IPv6 辅助和兼容性函数

 

接口

const char* evutil_inet_ntop(int af, const void * src, char * dst, size_t len);int evutil_inet_pton(int af, const char* src, void * dst);

这些函数根据 RFC 3493的规定解析和格式化IPv4IPv6地址,与标准inet_ntop()inet_pton()函数行为相同.要格式化IPv4地址,调用evutil_inet_ntop(),设置afAF_INET ,src指向in_addr结构体,dst指向大小为len的字符缓冲区.对于IPv6地址,af应该是AF_INET6,src则指向in6_addr结构体.要解析IP地址,调用evutil_inet_pton(),设置afAF_INET或者AF_INET6,src指向要解析的字符串,dst指向一个in_addr或者in_addr6结构体.失败时evutil_inet_ntop()返回NULL,成功时返回到dst的指针.成功时evutil_inet_pton()返回0,失败时返回-1.

 

接口

int evutil_parse_sockaddr_port(const char* str, struct sockaddr * out,int* outlen);

这个接口解析来自 str的地址,将结果写入到out.outlen参数应该指向一个表示out

可用字节数的整数;函数返回时这个整数将表示实际使用了的字节数.成功时函数返回0,

失败时返回-1.函数识别下列地址格式:

  • [ipv6]:port([ffff::]:80)

  • ipv6:(ffff::)

  • [ipv6]:([ffff::])

  • ipv4:port:(1.2.3.4:80)

  • ipv4:(1.2.3.4)


如果没有给出端口号,结果中的端口号将被设置为0.

 

接口

int evutil_sockaddr_cmp(const struct sockaddr* sa1,const struct sockaddr* sa2, int include_port);

evutil_sockaddr_cmp()函数比较两个地址,如果sa1sa2前面,返回负数;如果二者相等,则返回0;如果sa2sa1前面,则返回正数.函数可用于AF_INETAF_INET6地址;对于其他地址,返回值未定义.函数确保考虑地址的完整次序,但是不同版本中的次序可能不同.

 

如果 include_port参数为false,而两个地址只有端口号不同,则它们被认为是相等的.否则,具有不同端口号的地址被认为是不等的.

 

evutil_sockaddr_cmp()2.0.3-alpha版本引入外,这些函数在2.0.1-alpha版本中引入.

 

9.7结构体可移植函数

 

接口

#define evutil_offsetof(type, field) /* ...*/

跟标准 offsetof宏一样,这个宏返回从type类型开始处到field字段的字节数.这个宏由2.0.1-alpha版本引入,2.0.3-alpha版本之前是有bug.

 

9.8安全随机数发生器

很多应用(包括evdns)为了安全考虑需要很难预测的随机数

 

接口

void evutil_secure_rng_get_bytes(void* buf, size_t n);

这个函数用随机数据填充 buf处的n个字节.如果所在平台提供了arc4random(),libevent会使用这个函数.否则,libevent会使用自己的arc4random()实现,种子则来自操作系统的熵池(entropy pool)(Windows中的CryptGenRandom,其他平台中的/dev/urandom).

 

接口

int evutil_secure_rng_init(void);void evutil_secure_rng_add_bytes(const char* dat, size_t datlen)

不需要手动初始化安全随机数发生器,但是如果要确认已经成功初始化,可以调 用evutil_secure_rng_init().函数会播种RNG(如果没有播种过) ,并在成功时返回0.函数返回-1则表示libevent无法在操作系统中找到合适的熵源(source of entropy) ,如果不自己初始化RNG,就无法安全使用RNG.

 

如果程序运行在可能会放弃权限的环境中(比如说,通过执行chroot()) ,在放弃权限前应该调用evutil_secure_rng_init().可以调用evutil_secure_rng_add_bytes()向熵池加入更多随机字节,但通常不需要这么做.这些函数是2.0.4-alpha版本引入的.





<<下一章>>


0 0