libevent(一) socket屬性設置與初始化操作

socket屬性設置與初始化操作

libevent是一個事件觸發的網絡庫,適用於windows、linux、bsd等多種平臺,內部使用select、epoll、kqueue等系統調用管理事件機制。著名分佈式緩存軟件memcached也是libevent based,而且libevent在使用上可以做到跨平臺,而且根據libevent官方網站上公佈的數據統計,似乎也有着非凡的性能。

event_base

在使用Libevent之前,需要初始化一個event_base結構。每一個event_base結構提包含了events集合並選擇事件類型。如果選擇locking方式,會保證交互是線程安全的。如果需要使用多線程模型的話,需要爲每一個線程建立一個event_base。

method種類

select、poll、epoll、kqueue、devpoll、evport、win32

接口

#include <event2/event.h>
struct event_base *event_base_new(void);

`event_base_new`會根據默認的配置參數返回一個`event_base`結構體,失敗返回`NULL`。

配置方法

struct event_config *event_config_new(void);
struct event_base *event_base_new_with_config(const struct event_config *cfg);
void event_config_free(struct event_config *cfg);

`event_config_new`可以返回一個配置信息的結構體,通過修改結構提內容,並作爲參數傳遞給`event_base_new_with_config`可以生成目標`event_base`,而`event_config_free`使用來是放掉config配置信息的。

那麼event_config到底是什麼樣的?

struct event_config {
    TAILQ_HEAD(event_configq, event_config_entry) entries;
    int n_cpus_hint; //cpu數量
    enum event_method_feature require_features;//指定IO複用的條件
    enum event_base_config_flag flags;
};

可以使用`event_config_set_num_cpus_hint(struct event_config *cfg, int cpus)`設置`n_cpu_hint`,但是目前只支持使用IOCP的情況下。

`require_features`的具體結構如下:

複製代碼
//event.h文件
enum event_method_feature {
    //支持邊沿觸發
    EV_FEATURE_ET = 0x01,
    //添加、刪除、或者確定哪個事件激活這些動作的時間複雜度都爲O(1)
    //select、poll是不能滿足這個特徵的.epoll則滿足
    EV_FEATURE_O1 = 0x02,
    //支持任意的文件描述符,而不能僅僅支持套接字
    EV_FEATURE_FDS = 0x04
};
複製代碼

通過`event_config_require_features(struct event_config *cfg, int features)`函數來設置`require_features`。

需要注意的是,當需要設置多個參數的時候需要使用 `EV_FEATURE_O1 | EV_FEATURE_FDS`操作,而不是多次調用該函數。如果設置不當,找不當對應的事件方法method,`event_base_new_with_config(cfg)會返回NULL`。

最後一個參數`flag`指定其他的配置:

複製代碼
enum event_base_config_flag {
    //不分配鎖(如果設置,保證線程安全)
    EVENT_BASE_FLAG_NOLOCK = 0x01,
    //不檢測EVENT_*環境變量?
    EVENT_BASE_FLAG_IGNORE_ENV = 0x02,
    //win下的iocp
    EVENT_BASE_FLAG_STARTUP_IOCP = 0x04, 
    //?
    EVENT_BASE_FLAG_NO_CACHE_TIME = 0x08,
    //如果決定使用epoll這個多路IO複用函數,可以安全地使用更快的基於    changelist 的多路IO複用函數
    EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST = 0x10,
    //?
    EVENT_BASE_FLAG_PRECISE_TIMER = 0x20
};
複製代碼

通過`event_config_set_flag(struct event_config *cfg, enum event_base_config_flag flag)`進行設置。

獲取支持的配置

複製代碼
//獲取當前系統支持的IO複用方法
const char **event_get_supported_methods(void);
//獲取配置的IO複用方法
const char *event_base_get_method(const struct event_base *);
int event_base_get_features(const struct event_base *base);
//指明某個參數是否被禁用
static int event_config_is_avoided_method(const struct event_config *cfg, const char *method)
複製代碼

設置IO優先級

默認情況下會設置相同的優先級。

int event_base_priority_init(struct event_base *base, int n_priorities);
int event_base_get_npriorities(struct event_base *base);

fork使用parent進程中的event_base

複製代碼
int event_reinit(struct event_base *base);

#include <event2/event.h>
/* example */
struct event_base *base = event_base_new();
/* ... add some events to the event_base ... */
if (fork()) {
    /* In parent */
    continue_running_parent(base); /*...*/
} else {
    /* In child */
    event_reinit(base);
    continue_running_child(base); /*...*/
}
複製代碼

 

libevent 函數

考慮到多個平臺的兼容性(並不是所有平臺都支持某一函數功能),`libevent`自身提供了很多函數以及數據類型,下面的函數均是是跨平臺的,在Unix以及windows都可以正常運行。

定時函數

#define evutil_timeradd(tvp, uvp, vvp) /* 增加 vvp=tvp+uvp */
#define evutil_timersub(tvp, uvp, vvp) /* 減少 vvp=tvp-uvp */
#define evutil_timercmp(tvp, uvp, cmp) /* 比較 if (cmp=='<'), then ("tvp < uvp") */
int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
/* Set tv = now */
evutil_gettimeofday(&tv, NULL);

 

複製代碼
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.")
複製代碼

兼容的Socket接口

關閉socket:在`unix`中,只需要調用`close()`,而在`windows`中需要調用`closesocket()`。

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

獲取socket錯誤信息

#define EVUTIL_SOCKET_ERROR() /* 獲取最新的全局錯誤信息 */
#define EVUTIL_SET_SOCKET_ERROR(errcode) /* 改變錯誤信息,等於設置錯誤 */
#define evutil_socket_geterror(sock) /* 指定sockfd,同1 */
#define evutil_socket_error_to_string(errcode) /* 把errcode轉換爲字符串 */

設置非阻塞模式

int evutil_make_socket_nonblocking(evutil_socket_t sock);

地址重用

int evutil_make_listen_socket_reuseable(evutil_socket_t sock);

socketpair
該函數和unix中的socketpair一樣,它會產生兩個連接socket,一個用於輸入,一個用於輸出。注意,在windows中,只支持family=AF_INET,type=SOCK_STREAM,protocol=0。

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

隨機數生成

該函數生成n長度的buf數據

void evutil_secure_rng_get_bytes(void *buf, size_t n);

參考

http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html
http://www.tuicool.com/articles/jaQ7vmZ

本文 由 cococo點點 創作,採用 知識共享 署名-非商業性使用-相同方式共享 3.0 中國大陸 許可協議進行許可。歡迎轉載,請註明出處:
轉載自:cococo點點 http://www.cnblogs.com/coder2012

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章