Libevent初探

Libevent 是一個用C語言編寫的、輕量級的開源高性能網絡庫,主要有以下幾個亮點:事件驅動( event-driven),高性能;輕量級,專注于網絡,不如 ACE 那么臃腫龐大;源代碼相當精煉、易讀;跨平臺,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多種 I/O 多路復用技術, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定時器和信號等事件;注冊事件優先級。
Libevent 已經被廣泛的應用,作為底層的網絡庫;比如 memcached、 Vomit、 Nylon、 Netchat等等。Libevent之于C語言網絡編程,類似于Nettty之于Java Web編程。學習Netty的小伙伴,不防看下Libevent的實現,會加深對Netty框架的理解~
Libevent的安裝教程網上較多,LZ在此就不再贅述,下面直接來點干貨-Libevent如何使用。

檢查Libevent支持的IO復用方法

Libevent作為一個高性能網絡庫,內部封裝了多種IO復用技術,如果想看下Libevent在當前系統下支持哪些IO復用技術呢?
int main(int argc, char **argv)
{// 版本信息cout << event_get_version() << endl;// 所支持的IO復用方法const char **methods = event_get_supported_methods();for (int i = 0; methods[i] != NULL; i++) {cout << methods[i] << endl;}return 0;
}

輸出結果為:(Centos7 Clion 2016.1.3環境)

  event_get_supported_methods()函數返回Libevent支持的IO復用方法名稱數組,以NULL結尾。該函數實際返回的是全局變量eventops數組,eventops數組存放的是所有支持的IO復用函數,eventops聲明部分的代碼如下:

/* Array of backends in order of preference. */
/* Libevent通過遍歷eventops數組來選擇其后端IO復用技術,遍歷的順序是從數組的第一個元素開始,* 到最后一個元素結束。Linux系統下,默認選擇的后端IO復用技術是epoll。*/
static const struct eventop *eventops[] = {
#ifdef _EVENT_HAVE_EVENT_PORTS&evportops,
#endif
#ifdef _EVENT_HAVE_WORKING_KQUEUE&kqops,
#endif
#ifdef _EVENT_HAVE_EPOLL&epollops,
#endif
#ifdef _EVENT_HAVE_DEVPOLL&devpollops,
#endif
#ifdef _EVENT_HAVE_POLL&pollops,
#endif
#ifdef _EVENT_HAVE_SELECT&selectops,
#endif
#ifdef WIN32&win32ops,
#endifNULL
};

Libevent是如何打日志的

libevent的錯誤處理底層調用的是va_start/va_end等相關宏,它們所在的頭文件是<stdarg.h>,使用C函數庫提供的這些函數,我們也可以實現一個自己的打日志程序,以下是一個使用va_start/va_end的測試程序:
void log(const char *fmt, ...)
{char buff[512];va_list ap;va_start(ap, fmt);int len = vsnprintf(buff, sizeof(buff), fmt, ap);buff[len] = '\0';va_end(ap);cout << buff << endl;
}
  • va_start:宏定義,引用最后一個固定參數所以它能夠對可變參數進行定位。
  • va_end:宏定義,函數返回之前一定要調用va_end,這是因為某些實現在函數返回之前需要調整控制信息。
使用上述函數,我們就可以愉快地打日志了,比如按照如下形式來調用:
log("hi, are you %s?", "luxon28");
log("name=%s, age=%d", "luoxn28", 23);

  更多va_start/va_end信息請點擊:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html。

定時器的使用

#include <iostream>#include <event.h>
#include <event2/http.h>using namespace std;// Time callback function
void onTime(int sock, short event, void *arg)
{static int cnt = 0;cout << "Game Over! " << cnt++ << endl;struct timeval tv;tv.tv_sec = 1;tv.tv_usec = 0;if (cnt < 5) {// Add timer eventevent_add((struct event *) arg, &tv);}else {cout << "onTime is over" << endl;}
}int main(int argc, char **argv)
{cout << event_get_version() << endl;struct event_base *base = event_init();struct event ev;evtimer_set(&ev, onTime, &ev);struct timeval timeevent;timeevent.tv_sec = 1;timeevent.tv_usec = 0;event_add(&ev, &timeevent);// Start event loopevent_base_dispatch(base);event_base_free(base);return 0;
}

輸出結果如下:

  LZ安裝的是Libevent版本是2.0版本,event_init()函數初始化一個事件類結構體,其中已經選擇好了IO復用函數,比如Linux下一般是epoll;初始化了一個事件活動隊列,當事件發生時,會被加入到該事件活動隊列中,然后統一執行事件活動隊列中的所有事件(也就是調用對應的回調函數)。event_base結構體詳細內容如下:

/* 結構體event_base是Libevent的Reactor */
struct event_base {/* 初始化Reactor時選擇的一種后端IO復用機制,并記錄在如下字段中 */const struct eventop *evsel;/* 指向IO復用機制真正存儲的數據,它通過evsel成員的init函數來進行初始化 */void *evbase;/* 事件變化隊列,其用途是:如果一個文件描述符上注冊的事件被多次修改,則可以使用緩沖區來避免重復的* 系統調用(比如epoll_wait)。它僅能用于時間復雜度為O(1)的IO復用技術 */struct event_changelist changelist;/* 指向信號的后端處理機制,目前僅在singal.h文件中定義了一種處理方法 */const struct eventop *evsigsel;/* 信號事件處理器使用的數據結構,其中封裝了一個由socketpair創建的管道。它用于信號處理函數和* 事件多路分發器之間的通信 */struct evsig_info sig;/* 以下3個成員是添加到該event_base的虛擬事件、所有事件和激活事件的數量 */int virtual_event_count;int event_count;int event_count_active;/* 是否執行完活動事件隊列上的剩余的任務之后就退出事件處理 */int event_gotterm;/* 是否立即退出事件循環,而不管是否還有任務需要處理 */int event_break;/* 是否應該啟動一個新的事件循環 */int event_continue;/* 目前正在處理的活動事件隊列的優先級 */int event_running_priority;/* 事件循環是否啟動 */int running_loop;/* 活動事件隊列數組,索引值越小的隊列,優先級越高。高優先級的活動事件隊列中的事件處理器將被優先處理 */struct event_list *activequeues;/* 活動事件隊列數組的大小,即該event_base共有nactivequeues個不同優先級的活動事件隊列 */int nactivequeues;/* common timeout logic *//* 以下3個成員用于管理通用定時器隊列 */struct common_timeout_list **common_timeout_queues;int n_common_timeouts;int n_common_timeouts_allocated;/* 存放延時回調函數的鏈表,事件循環每次成功處理完一個活動事件隊列中的所有事件之后,* 就調用一次延遲回調函數 */struct deferred_cb_queue defer_queue;/* 文件描述符和IO事件之間的映射關系表 */struct event_io_map io;/* 信號值和信號事件之間的映射關系表 */struct event_signal_map sigmap;/* 注冊事件隊列,存放IO事件處理器和信號事件處理器 */struct event_list eventqueue;struct timeval event_tv;/* 時間堆 */struct min_heap timeheap;struct timeval tv_cache;#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)/** Difference between internal time (maybe from clock_gettime) and* gettimeofday. */struct timeval tv_clock_diff;/** Second in which we last updated tv_clock_diff, in monotonic time. */time_t last_updated_clock_diff;
#endif/* 多線程支持 */
#ifndef _EVENT_DISABLE_THREAD_SUPPORT/* threading support *//** The thread currently running the event_loop for this base *//* 當前運行該event_base的事件循環的線程 */unsigned long th_owner_id;/** A lock to prevent conflicting accesses to this event_base */void *th_base_lock;            /* 鎖變量 *//** The event whose callback is executing right now *//* 當前事件循環正在執行哪個事件處理器的回調函數 */struct event *current_event;/** A condition that gets signalled when we're done processing an* event with waiters on it. *//* 條件變量,用于喚醒正在等待某個事件處理完畢的線程 */void *current_event_cond;/** Number of threads blocking on current_event_cond. */int current_event_waiters;    /* 等待current_event_cond的線程數 */
#endif/** Flags that this base was configured with *//* 該vent_base的一些配置參數 */enum event_base_config_flag flags;/* 下面這些成員變量給工作線程喚醒主線程提供了方法(使用socketpair創建的管道) *//* Notify main thread to wake up break, etc. *//** True if the base already has a pending notify, and we don't need* to add any more. */int is_notify_pending;/** A socketpair used by some th_notify functions to wake up the main* thread. */evutil_socket_t th_notify_fd[2];/** An event used by some th_notify functions to wake up the main* thread. */struct event th_notify;/** A function used to wake up the main thread from another thread. */int (*th_notify_fn)(struct event_base *base);
}

  event_add()函數是往事件結構體中加入監聽的一個事件,這里是定時事件,當定時事件到時,就會執行對應的回調函數。event_base_dispatch()函數開始執行事件監聽,對應于epoll的話也就是調用epoll_wait了。最后,當程序執行完畢后,需要調用event_base_free()函數來執行資源的銷毀操作,至此,整個定時器事件就執行完畢了。

?

簡單的HTTP服務器

  使用Libevent,我們可以用不超過50行代碼實現一個簡單的HTTP服務器程序,沒有聽錯,就是幾十行代碼,不像Java那樣,需要配置Tomcat,然后編寫對應的Servet,配置web.xml等等(如果使用SSM或者SSH的話步驟或許更多一點呦 :( )。下面就是一個簡單的HTTP服務器示例代碼:

#include <iostream>#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/http.h>using namespace std;#define INFO 1
#define ERR  3
static void log(int level, string info)
{switch (level) {case INFO:cout << "[info] tid[" << pthread_self() << "]: " << info << endl;break;case ERR:cout << "[err] tid[" << pthread_self() << "]: " << info << endl;break;default:break;}
}/*** http callback function*/
void httpHandler(struct evhttp_request *request, void *arg) {struct evbuffer *buff = evbuffer_new();if (!buff) {log(INFO, "evbuffer_new error");return;}evbuffer_add_printf(buff, "Hello world</br>");evbuffer_add_printf(buff, "Server Responsed.</br> Requested: %s<br/>", evhttp_request_get_uri(request));evbuffer_add_printf(buff, " Host: %s<br/>", evhttp_request_get_host(request));evbuffer_add_printf(buff, " Command: %d", evhttp_request_get_command(request));evhttp_send_reply(request, HTTP_OK, "OK", buff);evbuffer_free(buff);
}int main(int argc, char **argv)
{struct event_base *base = event_base_new();struct evhttp *httpServer = evhttp_new(base);int result = evhttp_bind_socket(httpServer, NULL, 8080);if (result != 0) {log(ERR, "evhttp_bind_socket error");return -1;}/* 這是http回調函數 */evhttp_set_gencb(httpServer, httpHandler, NULL);cout << "Http server start OK..." << endl;event_base_dispatch(base);evhttp_free(httpServer);event_base_free(base);return 0;
}

  訪問頁面如下,192.168.1.150主機是linux服務器。

  看到這里,學習Java Web的小伙伴是不是覺得很熟悉,沒錯,就是像Servlet。LZ個人覺得,對于小型程序來說,使用C/C++的網絡庫編程程序更爽一點,因為更加"接地氣?"一點,也就操作起來更加靈活,使用Java的話肯定要使用Servet容器了,比如Tomcat或者Jboss等,然后各種配置等。但是對于動態Web技術來說,使用Java更爽一點。

參考資料
1、libevent-百度百科
2、Libevent部分源碼

轉載于:https://www.cnblogs.com/luoxn28/p/5813860.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457342.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457342.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457342.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ServerSocketChannel API用法

java.nio.channels 類 ServerSocketChannel java.lang.Objectjava.nio.channels.spi.AbstractInterruptibleChanneljava.nio.channels.SelectableChanneljava.nio.channels.spi.AbstractSelectableChanneljava.nio.channels.ServerSocketChannel所有已實現的接口&#xff1a; C…

jq分頁 不刷新頁面_jQuery無刷新分頁完整實例代碼

本文實例講述了jQuery無刷新分頁實現方法。分享給大家供大家參考&#xff0c;具體如下&#xff1a;這款jQuery分頁示例&#xff0c;是分頁經典形式&#xff0c;兼容性也做的好&#xff0c;網頁上的分頁代碼&#xff0c;分享給大家。運行效果截圖如下&#xff1a;在線演示地址如…

為什么要寫年終總結

2016只剩下不到百分之一的時間了&#xff0c;網上陸續看到各種企業或個人的總結或盤點&#xff0c;公司也必須規定每個員工要做年度工作總結&#xff0c;或許是環境釋然&#xff0c;心里也有無數次要做總結的念頭&#xff0c;尤其是月末年末這種感覺更重&#xff0c;但卻沒靜下…

特別慢_背什么都特別慢,該怎么提高記憶力?

考研是一項全方位的比拼&#xff0c;除了每天進行知識點的復習&#xff0c;還要做題、總結&#xff0c;最后還得進行背誦記憶&#xff0c;其實什么科目都需要背的&#xff0c;就算數學&#xff0c;該記的概念和公式也是要記憶的&#xff0c;因為會做題更快&#xff0c;提高效率…

tiny4412u-boot燒寫及根文件系統制作(不進入終端問題)

http://m.blog.csdn.net/article/details?id51400196&#xff08;轉&#xff09; VMware12 環境&#xff1a;ubuntu12.4 開發板&#xff1a;tiny4412 首先燒寫bootloader&#xff0c;我用一個8G的內存卡&#xff0c;現在不說sd卡的制作過程了&#xff0c;網上可以參考。 現在就…

第三章 中間件,3.1 萬億級數據洪峰下的分布式消息引擎(作者:馮嘉、誓嘉、塵央、牟羽)...

3.1 萬億級數據洪峰下的分布式消息引擎 前言 通過簡單回顧阿里中間件(Aliware)消息引擎的發展史&#xff0c;本文開篇于雙11消息引擎面臨的低延遲挑戰&#xff0c;通過經典的應用場景闡述可能會面臨的問題 - 響應慢&#xff0c;雪崩&#xff0c;用戶體驗差&#xff0c;繼而交易…

Linux目錄結構和常用命令

一、Linux目錄結構 你想知道為什么某些程序位于/bin下&#xff0c;或者/sbin&#xff0c;或者/usr/bin&#xff0c;或/usr/sbin目錄下嗎&#xff1f;例如&#xff0c;less命令位于/usr/bin目錄下。為什么沒在/bin中&#xff0c;或/sbin&#xff0c;或/usr/sbin目錄中&#xff1…

掛載nfs文件系統_綜合架構-day38-NFS服務補充

1.如何讓nfs永久掛載-2種方法開機自啟動文件1.vim /etc/rc.d/rc.local需要修改執行權限chmod x /etc/rc.d/rc/localmount -t nfs 172.16.1.31:/upload/ /mnt/2.vim /etc/fstab172.16.1.31:/upload /mnt nfs defaults 0 02.exportfs 加載配置生效&#xff0c;等價于優雅重啟[15:…

A Neural Algorithm of Artistic Style

本系列文章由 yhl_leo 出品&#xff0c;轉載請注明出處。 文章鏈接&#xff1a; http://blog.csdn.net/yhl_leo/article/details/53931536 1. 資源 Paper: A Neural Algorithm of Artistic StyleTensorFlow version in GitHub: anishathalye/neural-styleCaffe version in GitH…

CSS布局奇淫技巧之--各種居中

居中是我們使用css來布局時常遇到的情況。使用css來進行居中時&#xff0c;有時一個屬性就能搞定&#xff0c;有時則需要一定的技巧才能兼容到所有瀏覽器&#xff0c;本文就居中的一些常用方法做個簡單的介紹。 注&#xff1a;本文所講方法除了特別說明外&#xff0c;都是兼容I…

手寫數字識別中多元分類原理_廣告行業中那些趣事系列:從理論到實戰BERT知識蒸餾...

導讀&#xff1a;本文將介紹在廣告行業中自然語言處理和推薦系統實踐。本文主要分享從理論到實戰知識蒸餾&#xff0c;對知識蒸餾感興趣的小伙伴可以一起溝通交流。摘要&#xff1a;本篇主要分享從理論到實戰知識蒸餾。首先講了下為什么要學習知識蒸餾。一切源于業務需求&#…

linux zip/unzip命令

2019獨角獸企業重金招聘Python工程師標準>>> 語  法&#xff1a;zip [-AcdDfFghjJKlLmoqrSTuvVwXyz$][-b <工 作目錄>][-ll][-n <字 尾字符串>][-t <日 期時間>][-<壓 縮效率>][壓 縮文件][文件...][-i <范本樣式>][-x <范本樣式…

離散事件模擬

1. 離散事件系統模擬 被模擬系統的行為&#xff1a; 可以抽象為一些離散事件的發生&#xff1b;所發生事件可以引發新的事件&#xff08;拓撲序&#xff09;&#xff1b;人們希望通過計算機模擬理解系統行為&#xff0c;評價或設計真實世界中實際的或所需的系統&#xff1b;適用…

epoll邊緣觸發_C++回聲服務器_9-epoll邊緣觸發模式版本服務器

epoll默認情況下是水平觸發模式&#xff0c;這次將epoll設置為邊緣觸發模式來實現服務器&#xff0c;而客戶端直接使用完美回聲服務器的客戶端。服務器代碼#include #include #include #include #include #include #include #include #include const int BUF_SIZE 4;const int…

利用dbstart和dbshut腳本自動啟動和停止數據庫的問題

客戶的兩臺IBM Power 740小型機使用HACMP軟件創建互備關系的數據庫服務器&#xff0c;每臺小型機運行一個數據庫&#xff0c;任何一臺服務器出現故障宕機&#xff0c;另一臺小型機應該立即接管&#xff0c;且要一并接管數據庫&#xff0c;這時在一臺小型機上就運行了兩個數據庫…

在Windows下不使用密碼遠程登陸Linux

在登陸Linux進行管理的時候我們通常會使用用戶名和密碼進行登陸&#xff0c;這樣一來是比較麻煩&#xff0c;二來是不安全&#xff0c;為了解決這個問題&#xff0c;我們可以使用公私鑰 (public keys和private keys)進行認證。簡單來說公鑰存放在服務器上&#xff0c;私鑰存放在…

dto 是只給前端需要的數據嗎_DO、VO、DTO...XXOO,你弄明白了么

技術公眾號&#xff1a;Java In Mind(Java_In_Mind),歡迎關注&#xff01;背景我相信&#xff0c;剛開始學習接觸企業代碼的時候&#xff0c;一定會發現&#xff0c;工程中充斥著各種XO&#xff1a;DO、VO、DTO、DAO&#xff0c;還有各種名詞&#xff1a;POJO&#xff0c;JavaB…

Javascript判斷object還是list/array的類型(包含javascript的數據類型研究)

前提&#xff1a;先研究javascript中的變量有幾種&#xff0c;參考&#xff1a; http://www.w3school.com.cn/js/js_datatypes.asp http://glzaction.iteye.com/blog/1285147 測試1&#xff1a; typeof關鍵字 var obj {test:test}; typeof obj;//輸出object var list [{test:t…

Core Data

簡介 Core Data是iOS5之后才出現的一個框架&#xff0c;它提供了對象-關系映射(ORM)的功能&#xff0c;即能夠將OC對象轉化成數據&#xff0c;保存在SQLite數據庫文件中&#xff0c;也能夠將保存在數據庫中的數據還原成OC對象。在此數據操作期間&#xff0c;我們不需要編寫任何…

tbase同步mysql_mysql主從同步

MySQL主從介紹MySQL主從叫做Replication、AB復制&#xff0c;A和B做主從后&#xff0c;在A上寫數據。B上也會同步A的數據&#xff0c;兩者實現實時同步MySQL是基于binlog日志來同步的&#xff0c;主上必須開啟binlog才能進行主從同步&#xff0c;同步過程大概有三個步驟(1)主將…