源碼安裝的方式(終端打開(kāi)下載" />

在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Libevent網(wǎng)絡(luò)庫(kù)的原理與應(yīng)用

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-09 10:24 ? 次閱讀

1. Libevent介紹

Libevent 是一個(gè)用C語(yǔ)言編寫(xiě)的、輕量級(jí)的開(kāi)源高性能事件通知庫(kù),主要有以下幾個(gè)亮點(diǎn):

    • 事件驅(qū)動(dòng)( event-driven),高性能;
    • 源代碼相當(dāng)精煉、易讀;
    • 跨平臺(tái),支持 Windows、 Linux、 BSD(是Unix的衍生系統(tǒng)) 和 Mac OS;
    • 支持多種 I/O 多路復(fù)用技術(shù), epoll、 poll、 select 和 kqueue 等;
    • 支持注冊(cè)事件優(yōu)先級(jí)。

1.1 安裝Libevent

下載地址: http://http://libevent.org/

安裝步驟 -> 源碼安裝的方式(終端打開(kāi)下載目錄)

1. 可執(zhí)行程序: configure
          ./configure         // 檢測(cè)安裝環(huán)境, 并且生成一個(gè)makefile文件

      2. 根據(jù)makefile中的構(gòu)建規(guī)則編譯源代碼
          make     

      3. 安裝
          sudo make install   //將得到可執(zhí)行程序/動(dòng)態(tài)庫(kù)/靜態(tài)庫(kù)/頭文件拷貝到系統(tǒng)目錄

動(dòng)態(tài)庫(kù)找不到問(wèn)題解決:

  1. 通過(guò)find命令查找對(duì)應(yīng)的庫(kù)的位置

find 搜索目錄 -name "http://libevent.so"

得到結(jié)果: /usr/local/lib/libevent.so

  1. 通過(guò)vi 打開(kāi)/etc/ld.so.conf文件

sudo /etc/ld.so.conf

將/usr/local/lib/放到文件的最后一行, 保存

  1. 執(zhí)行命令: sudo ldconfig

編譯要加上動(dòng)態(tài)庫(kù)event hello.c

gcc hello.c -o hello -levent

2. 事件處理框架 - event_base

使用 libevent函數(shù)之前需要分配一個(gè)或者多個(gè) event_base 結(jié)構(gòu)體。每個(gè)event_base 結(jié)構(gòu)體持有一個(gè)事件集合,可以檢測(cè)以確定哪個(gè)事件是激活的。每個(gè) event_base 都有一種用于檢測(cè)哪種事件已經(jīng)就緒的 “方法”。

2.1 event_base API函數(shù)

// 頭文件
  #include < event2/event.h >
  // 操作函數(shù)
  struct event_base * event_base_new(void);          //創(chuàng)建事件處理框架
  void event_base_free(struct event_base * base);    //釋放事件處理框架

  // 檢查event_base的后端方法
  const char** event_get_supported_methods(void);
  const char *event_base_get_method(const struct event_base *base);

event_base和fork(進(jìn)程)關(guān)系:

  1. 子進(jìn)程創(chuàng)建成功之后, 父進(jìn)程可以繼續(xù)使用event_base
  2. 子進(jìn)程中需要繼續(xù)使用event_base需要用下面函數(shù),重新初始化
int event_reinit(struct event_base* base);

例子:

#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < string.h >
#include < event2/event.h >

int main()
{
    // 1. 創(chuàng)建事件處理框架
    struct event_base* base = event_base_new();

    // 打印支持的IO轉(zhuǎn)接函數(shù)
    const char** method = event_get_supported_methods();
    for(int i=0; method[i] != NULL; ++i)
    {
        printf("%sn", method[i]);
    }
    printf("current method: %sn", event_base_get_method(base));

    // 創(chuàng)建子進(jìn)程
    pid_t pid = fork();
    if(pid == 0)
    {
        // 子進(jìn)程中event_base也會(huì)被復(fù)制,在使用這個(gè)base時(shí)候要重新初始化
        event_reinit(base); 
    }

    // 2. 釋放資源
    event_base_free(base);
    return 0;
}

3. 事件循環(huán)

event_base不停的檢測(cè)委托的檢測(cè)是實(shí)際是不是發(fā)生了, 如果發(fā)生了, event_base會(huì)調(diào)用對(duì)應(yīng)的回調(diào)函數(shù), 這個(gè)回調(diào)函數(shù)的用戶(hù)委托檢測(cè)事件的時(shí)候給的.

3.1 設(shè)置事件循環(huán)

如果委托了event_base檢測(cè)某些事件, 不停的進(jìn)行循環(huán)檢測(cè)
結(jié)束檢測(cè)時(shí)間: 所有要檢測(cè)的事件都被觸發(fā), 并且處理完畢。

// 頭文件
  #include < event2/event.h >

  // 操作函數(shù)
  #define EVLOOP_ONCE 			0x01
  #define EVLOOP_NONBLOCK 		0x02
  #define EVLOOP_NO_EXIT_ON_EMPTY 0x04

  int event_base_loop(struct event_base *base, int flags);
  	參數(shù):
  		- base: 通過(guò) event_base_new(void)得到的
  		- flags:
  			- EVLOOP_ONCE: 一直檢測(cè)某個(gè)事件, 當(dāng)事件被觸發(fā)了, 停止事件循環(huán)
  			- EVLOOP_NONBLOCK: 非阻塞的方式檢測(cè), 當(dāng)事件被觸發(fā)了, 停止事件循環(huán)
  			- EVLOOP_NO_EXIT_ON_EMPTY: 一直進(jìn)行事件檢測(cè), 如果沒(méi)有要檢測(cè)的事件, 不退出

  int event_base_dispatch(struct event_base* base); 	// 一般使用這個(gè)函數(shù)
  	參數(shù):
  		- base: 通過(guò) event_base_new(void)得到的

3.2 終止事件循環(huán)

// 頭文件
  #include < event2/event.h >

  struct timeval {
  	long    tv_sec;                    
  	long    tv_usec;    // 微秒        
  };

  // 在 tv 時(shí)長(zhǎng)之后退出循環(huán), 如果這個(gè)參數(shù)為空NULL, 直接退出事件循環(huán)
  // 事件循環(huán): 檢測(cè)對(duì)應(yīng)的事件是否被觸發(fā)了
  // 如果事件處理函數(shù)正在被執(zhí)行, 執(zhí)行完畢之后才終止
  int event_base_loopexit(struct event_base * base, const struct timeval * tv);

// 馬上終止
  int event_base_loopbreak(struct event_base * base);

4. 事件

4.1 事件基本操作

  • 事件的創(chuàng)建 event_new
#include < event2/event.h >

//要檢測(cè)事件   what:
  #define EV_TIMEOUT 	0x01
  #define EV_READ 	    0x02
  #define EV_WRITE 	    0x04
  #define EV_SIGNAL 	0x08
  #define EV_PERSIST 	0x10	// 修飾某個(gè)事件是持續(xù)觸發(fā)的
  #define EV_ET 		0x20	// 邊沿模式

//回調(diào)函數(shù)格式:
  typedef void (*event_callback_fn)(evutil_socket_tshortvoid *);
  	參數(shù):
  		- 第一個(gè)參數(shù): event_new的第二個(gè)參數(shù)
  		- 第二個(gè)參數(shù): 實(shí)際觸發(fā)的事件
  		- 第三個(gè)參數(shù): event_new的最后一個(gè)參數(shù)

// 創(chuàng)建事件
  struct event* event_new(struct event_base * base,evutil_socket_t fd,
       					 short what,event_callback_fn cb,void * arg);
  	參數(shù):
  		- base: event_base_new得到的
  		- fd: 文件描述符, 檢測(cè)這個(gè)fd對(duì)應(yīng)的事件
  		- what: 監(jiān)測(cè)fd的什么事件 
  		- cb: 回調(diào)函數(shù), 當(dāng)前檢測(cè)的事件被觸發(fā), 這個(gè)函數(shù)被調(diào)用
  		- arg: 給回調(diào)函數(shù)傳參
  • 事件的釋放
#include < event2/event.h >
// 釋放事件資源
  void event_free(struct event * event);
  • 事件的添加、刪除

事件被new出之后, 不能直接被event_base進(jìn)行檢測(cè)event_add之后event_base就可以對(duì)事件進(jìn)行檢測(cè)

#include < event2/event.h >
int  event_add(struct event * ev,const  struct timeval * tv);
  	參數(shù): tv- > 超時(shí)時(shí)間, 
          如果這個(gè)值 > 0, 比如 == 3
          檢測(cè)fd的讀事件, 在三秒之內(nèi)沒(méi)有觸發(fā)該事件 - > 超時(shí)- > 超時(shí)之后, 事件對(duì)應(yīng)的回調(diào)函數(shù)會(huì)被強(qiáng)制調(diào)用
          如果該參數(shù)為NULL, 不會(huì)做超時(shí)檢測(cè)

// 刪除要檢測(cè)的事件
  int  event_del(struct event * ev);

4.2 事件的優(yōu)先級(jí)設(shè)置

// 頭文件
  #include < event2/event.h >

  // EVENT_MAX_PRIORITIES == 256     最大的初始化事件優(yōu)先級(jí)

  int event_base_priority_init(struct event_base * baseint n_priorities);
  	參數(shù):
  		- n_priorities: 等級(jí)的個(gè)數(shù), 假設(shè) == 6
             也就是說(shuō)有6個(gè)等級(jí): 0,1,2,3,4,5, 0優(yōu)先級(jí)最高

  // 獲取當(dāng)前可用的等的個(gè)數(shù)
  int event_base_get_npriorities(struct event_base * base);
  // 給事件設(shè)置等級(jí)
  int event_priority_set(struct event *event, int priority);
  	參數(shù):
  		- event: 創(chuàng)建的事件
  		- priority: 要設(shè)置的等級(jí)

例子:使用event實(shí)現(xiàn)有名管道的進(jìn)程間通信myfifo

myfifo管道文件要提前創(chuàng)造好

讀端:

#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < string.h >
#include < event2/event.h >
#include < fcntl.h >

//讀的回調(diào)函數(shù)
void read_cb(evutil_socket_t fd, short what, void* arg)
{
    char buf[128];
    int count = read(fd, buf, sizeof(buf)+1);
    printf("read data: %s, %dn", buf, count);
    printf("read event: %sn", what & EV_READ ? "yes" : "no");
    printf("what: %dnn", what);
}

int main()
{
    int fd = open("myfifo", O_RDONLY);
    if (fd == -1)
    {
        perror("open");
        exit(0);
    }

    struct event_base* base = event_base_new();
    //創(chuàng)建事件
    struct event* ev = event_new(base, fd, EV_READ|EV_PERSIST, read_cb, NULL);
    //添加事件
    event_add(ev, NULL);
    //事件循環(huán)檢測(cè)
    event_base_dispatch(base);

    //釋放資源
    event_free(ev);
    event_base_free(base);
    return 0;
}

寫(xiě)端:

#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < string.h >
#include < event2/event.h >
#include < fcntl.h >

//讀的回調(diào)函數(shù)
void write_cb(evutil_socket_t fd, short what, void* arg)
{
    char buf[128];
    static int num = 0;
    sprintf(buf, "hello, %dn", num++);
    int count = write(fd, buf, sizeof(buf)+1);
    printf("wirte data: %s, %dn", buf, count);
    printf("wirte event: %sn", what & EV_WRITE ? "yes" : "no");
    printf("what: %dnn", what);
    sleep(3);
}

int main()
{
    int fd = open("myfifo", O_WRONLY);
    if (fd == -1)
    {
        perror("open");
        exit(0);
    }

    struct event_base* base = event_base_new();
    //創(chuàng)建事件
    struct event* ev = event_new(base, fd, EV_WRITE|EV_PERSIST, write_cb, NULL);
    //添加事件
    event_add(ev, NULL);
    //事件循環(huán)檢測(cè)
    event_base_dispatch(base);

    //釋放資源
    event_free(ev);
    event_base_free(base);
    return 0;
}

5. 帶緩沖區(qū)的事件

概念理解:

  1. bufferevent 理解:
    • 是libevent為IO緩沖區(qū)操作提供的一種通用機(jī)制
    • bufferevent 由一個(gè)底層的傳輸端口(如套接字 ), 一個(gè)讀取緩沖區(qū)和一個(gè)寫(xiě)入緩沖區(qū)組成。
    • 與通常的事件在底層傳輸端口已經(jīng)就緒, 可以讀取或者寫(xiě)入的時(shí)候執(zhí)行回調(diào)不同的是, bufferevent在讀取或者寫(xiě)入了足夠量的數(shù)據(jù)之后調(diào)用用戶(hù)提供的回調(diào)。
    • 每個(gè) bufferevent 有兩個(gè)數(shù)據(jù)相關(guān)的回調(diào)
    • 讀取回調(diào): 從底層傳輸端口讀取了任意量的數(shù)據(jù)之后會(huì)調(diào)用讀取回調(diào)(默認(rèn))
    • 寫(xiě)入回調(diào): 輸出緩沖區(qū)中足夠量的數(shù)據(jù)被清空到底層傳輸端口后寫(xiě)入回調(diào)會(huì)被調(diào)用(默認(rèn))

創(chuàng)建/釋放基于套接字的bufferevent bufferevent_socket_new

主要應(yīng)用于網(wǎng)絡(luò)套接字通信 -> socket()

struct bufferevent *bufferevent_socket_new(
  	struct event_base *base,
  	evutil_socket_t fd,
  	enum bufferevent_options options
  ); 
  	參數(shù):
  		- base: 處理事件的
  		- fd: 通信的文件描述符
  		- options: BEV_OPT_CLOSE_ON_FREE - > 自動(dòng)釋放底層資源
  	返回值: 得到帶緩沖區(qū)的事件變量

// 釋放資源
  void bufferevent_free(struct bufferevent *bev);

在bufferevent上啟動(dòng)連接服務(wù)器函數(shù) bufferevent_socket_connect

  1. 如果還沒(méi)有為bufferevent 設(shè)置套接字,調(diào)用函數(shù)將為其分配一個(gè)新的流套接字,并且設(shè)置為非阻塞的

例子:bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

  1. 如果已經(jīng)為 bufferevent 設(shè)置套接字,調(diào)用bufferevent_socket_connect() 將告知 libevent 套接字還未連接,直到連接成功之前不應(yīng)該對(duì)其進(jìn)行讀取或者寫(xiě)入操作。
  2. 連接完成之前可以向輸出緩沖區(qū)添加數(shù)據(jù)。
int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *address, int addrlen); 
  	參數(shù):
  		- bev: 帶緩沖區(qū)的事件, 里邊封裝 fd
  		- address: 要連接的服務(wù)器的IP和端口
  		- addrlen: address結(jié)構(gòu)體的內(nèi)存大小

bufferevent讀寫(xiě)緩沖區(qū)回調(diào)操作 bufferevent_setcb

//讀、寫(xiě)事件觸發(fā)之后的回調(diào)函數(shù)格式
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
  	參數(shù):
  		- bev: 從bufferevent_setcb函數(shù)中的第一個(gè)參數(shù)傳入的
  		- ctx: 從bufferevent_setcb函數(shù)中的最后第一個(gè)參數(shù)傳入的

//特殊事件的回調(diào)函數(shù)格式 		
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short events, void *ctx);
  	參數(shù):
  		- bev: 從bufferevent_setcb函數(shù)中的第一個(gè)參數(shù)傳入的
  		- events: 可以檢測(cè)到的事件
  			EV_EVENT_READING:讀取操作時(shí)發(fā)生某事件,具體是哪種事件請(qǐng)看其他標(biāo)志。
  			BEV_EVENT_WRITING:寫(xiě)入操作時(shí)發(fā)生某事件,具體是哪種事件請(qǐng)看其他標(biāo)志。
  			BEV_EVENT_ERROR:操作時(shí)發(fā)生錯(cuò)誤。關(guān)于錯(cuò)誤的更多信息,請(qǐng)調(diào)用 EVUTIL_SOCKET_ERROR()。
  			BEV_EVENT_TIMEOUT:發(fā)生超時(shí)。
  			BEV_EVENT_EOF:遇到文件結(jié)束指示。
  			BEV_EVENT_CONNECTED:請(qǐng)求的連接過(guò)程已經(jīng)完成 

void bufferevent_setcb(struct bufferevent *bufev, 
                       bufferevent_data_cb readcb, 		
                       bufferevent_data_cb writecb, 
                       bufferevent_event_cb eventcb, void *cbarg
);
  	參數(shù):
  		- bufev: 帶緩沖區(qū)的事件
  		- readcb: 讀事件觸發(fā)之后的回調(diào)函數(shù)
  		- writecb: 寫(xiě)事件觸發(fā)之后的回調(diào)函數(shù)
  		- eventcb: 特殊事件的回調(diào)函數(shù)
  		- cbarg: 給回調(diào)函數(shù)傳參

禁用、啟用緩沖區(qū)

可以啟用或者禁用 bufferevent 上的 EV_READ、EV_WRITE 或者 EV_READ | EV_WRITE 事件。
沒(méi)有啟用讀取或者寫(xiě)入事件時(shí), bufferevent 將不會(huì)試圖進(jìn)行數(shù)據(jù)讀取或者寫(xiě)入。

寫(xiě)緩沖區(qū)默認(rèn)是有效的,讀緩沖區(qū)默認(rèn)無(wú)效

// 設(shè)置某個(gè)事件有效
  void bufferevent_enable(struct bufferevent *bufev, short events); 

// 設(shè)置某個(gè)事件無(wú)效
  void bufferevent_disable(struct bufferevent *bufev, short events);

// 獲取緩沖區(qū)對(duì)應(yīng)的有效事件
  short bufferevent_get_enabled(struct bufferevent *bufev);

操作bufferevent中的數(shù)據(jù) bufferevent_write bufferevent_read

// 向bufferevent的輸出緩沖區(qū)添加數(shù)據(jù)
  int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);

// 從bufferevent的輸入緩沖區(qū)移除數(shù)據(jù)
  size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);

6. 鏈接監(jiān)聽(tīng)器

  • 創(chuàng)建和釋放evconnlistener
#include < event2/listener.h > 

//回調(diào)函數(shù)格式
  typedef void (*evconnlistener_cb)(
  			struct evconnlistener *listener,   
  			evutil_socket_t sock,   
  			struct sockaddr *addr, 
  			int len, 
  			void *ptr
  ); 
  	參數(shù):
  		- listener: evconnlistener_new_bind 返回的地址
  		- sock: 用于通信的fd
  		- addr: 客戶(hù)端的地址信息
  		- ptr: 外部傳進(jìn)來(lái)的參數(shù), evconnlistener_new_bind的第三個(gè)參數(shù)
  		

// 創(chuàng)建監(jiān)聽(tīng)的套接字, 綁定, 設(shè)置監(jiān)聽(tīng), 等待并接受連接請(qǐng)求
  struct evconnlistener *evconnlistener_new_bind(
  			struct event_base *base,    
  			evconnlistener_cb cb,	        // 接受新連接之后的回調(diào)函數(shù)
  			void *ptr,                      // 回調(diào)函數(shù)參數(shù)
  			unsigned flags, 
  			int backlog,                   // listen()中的第二參數(shù),最多的監(jiān)聽(tīng)數(shù)量,小于128的整數(shù)
  			const struct sockaddr *sa,     // 本地的IP和端口
  			int socklen				   // struct sockaddr結(jié)構(gòu)體大小
  );
  	參數(shù):
  		- flags:
  			LEV_OPT_CLOSE_ON_FREE: 自動(dòng)關(guān)閉底層套接字
  			LEV_OPT_REUSEABLE: 設(shè)置端口復(fù)用
// 釋放
  void evconnlistener_free(struct evconnlistener *lev);
  • 啟用和禁用 evconnlistener

設(shè)置無(wú)效之后, 就不監(jiān)聽(tīng)連接請(qǐng)求了

#include < event2/listener.h > 

  int evconnlistener_disable(struct evconnlistener *lev);
  int evconnlistener_enable(struct evconnlistener *lev);
  • 調(diào)整 evconnlistener 的回調(diào)函數(shù)
#include < event2/listener.h >

void evconnlistener_set_cb(struct evconnlistener *lev, evconnlistener_cb cb, void *arg);

7. 例子:用event實(shí)現(xiàn)服務(wù)器和客戶(hù)端tcp通信

服務(wù)器使用鏈接監(jiān)聽(tīng)器、帶緩沖區(qū)的事件

客戶(hù)端使用帶緩沖區(qū)的事件

服務(wù)器server代碼:

#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < string.h >
#include < arpa/inet.h >
#include < event2/event.h >
#include < event2/bufferevent.h >
#include < event2/listener.h >

// read緩沖區(qū)的回調(diào)
void read_cb(struct bufferevent* bev, void* arg)
{
    // 讀緩沖區(qū)的數(shù)據(jù)
    char buf[128];
    int len = bufferevent_read(bev, buf, sizeof(buf));
    printf("read data: len = %d, str = %sn", len, buf);

    // 回復(fù)數(shù)據(jù)
    bufferevent_write(bev, buf, len);
    printf("數(shù)據(jù)發(fā)送完畢...n");
}

// 寫(xiě)緩沖區(qū)的回調(diào)
// 調(diào)用的時(shí)機(jī): 寫(xiě)緩沖區(qū)中的數(shù)據(jù)被發(fā)送出去之后, 該函數(shù)被調(diào)用
void write_cb(struct bufferevent* bev, void* arg)
{

    printf("arg value: %sn", (char*)arg);
    printf("數(shù)據(jù)已經(jīng)發(fā)送完畢...xxxxxxxxxxxxn");
}

// 事件回調(diào)
void events_cb(struct bufferevent* bev, short event, void* arg)
{
    if(event & BEV_EVENT_ERROR)
    {
        printf("some error happened ...n");
    }
    else if(event & BEV_EVENT_EOF)
    {
        printf("server disconnect ...n");
    }
    // 終止連接
    bufferevent_free(bev);
}

// 接收連接請(qǐng)求之后的回調(diào)
void listener_cb(struct evconnlistener *listener,   
                evutil_socket_t sock,   
                struct sockaddr *addr, 
                int len, 
                void *ptr)
{
    // 通信
    // 使用帶緩沖區(qū)的事件對(duì)sock進(jìn)行包裝
    struct event_base* base = (struct event_base*)ptr;
    struct bufferevent* bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
    // 設(shè)置回調(diào)
    bufferevent_setcb(bev, read_cb, write_cb, events_cb, NULL);
    bufferevent_enable(bev, EV_READ);
}

int main()
{
    struct event_base * base = event_base_new();
    // 1. 創(chuàng)建監(jiān)聽(tīng)的套接字, 綁定, 設(shè)置監(jiān)聽(tīng), 等待并接受連接請(qǐng)求
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9898);    // 服務(wù)器監(jiān)聽(tīng)的端口
    addr.sin_addr.s_addr = INADDR_ANY;
    struct evconnlistener* listener = evconnlistener_new_bind(base, listener_cb, base, 
                                                               LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                                               100, (struct sockaddr*)&addr, sizeof(addr)); 

    event_base_dispatch(base);
    evconnlistener_free(listener);
    event_base_free(base);


    return 0;
}

客戶(hù)端client代碼:

#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < string.h >
#include < arpa/inet.h >
#include < event2/event.h >
#include < event2/bufferevent.h >

// read緩沖區(qū)的回調(diào)
void read_cb(struct bufferevent* bev, void* arg)
{
    printf("arg value: %sn", (char*)arg);
    // 讀緩沖區(qū)的數(shù)據(jù)
    char buf[128];
    int len = bufferevent_read(bev, buf, sizeof(buf));
    printf("read data: len = %d, str = %sn", len, buf);

    // 回復(fù)數(shù)據(jù)
    bufferevent_write(bev, buf, len);
    printf("數(shù)據(jù)發(fā)送完畢...n");
}

// 寫(xiě)緩沖區(qū)的回調(diào)
// 調(diào)用的時(shí)機(jī): 寫(xiě)緩沖區(qū)中的數(shù)據(jù)被發(fā)送出去之后, 該函數(shù)被調(diào)用
void write_cb(struct bufferevent* bev, void* arg)
{

    printf("arg value: %sn", (char*)arg);
    printf("數(shù)據(jù)已經(jīng)發(fā)送完畢...xxxxxxxxxxxxn");
}

// 事件回調(diào)
void events_cb(struct bufferevent* bev, short event, void* arg)
{
    if(event & BEV_EVENT_ERROR)
    {
        printf("some error happened ...n");
    }
    else if(event & BEV_EVENT_EOF)
    {
        printf("server disconnect ...n");
    }
    // 終止連接
    bufferevent_free(bev);
}

void send_msg(evutil_socket_t fd, short ev, void * arg)
{
    // 將寫(xiě)入到終端的數(shù)據(jù)讀出
    char buf[128];
    int len = read(fd, buf, sizeof(buf));
    // 發(fā)送給服務(wù)器
    struct bufferevent* bev = (struct bufferevent*)arg;
    bufferevent_write(bev, buf, len);
}

int main()
{
    struct event_base * base = event_base_new();
    // 1. 創(chuàng)建通信的套接字
    struct bufferevent* bufev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

    // 2. 連接服務(wù)器
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9898);    // 服務(wù)器監(jiān)聽(tīng)的端口
    inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr);
    // 這個(gè)函數(shù)調(diào)用成功, == 服務(wù)器已經(jīng)成功連接
    bufferevent_socket_connect(bufev, (struct sockaddr*)&addr, sizeof(addr));

    // 3. 通信
    // 給bufferevent的緩沖區(qū)設(shè)置回調(diào)
    bufferevent_setcb(bufev, read_cb, write_cb, events_cb, (void*)"hello, world");
    bufferevent_enable(bufev, EV_READ);

    // 創(chuàng)建一個(gè)普通的輸入事件
    struct event* myev = event_new(base, STDIN_FILENO, EV_READ|EV_PERSIST, send_msg, bufev);
    event_add(myev, NULL);


    event_base_dispatch(base);
    event_free(myev);
    event_base_free(base);


    return 0;
}

8. 總結(jié):

處理不帶緩沖區(qū)的事件:

  1. 創(chuàng)建事件處理框架event_base event_base_new()
  2. 創(chuàng)建新事件event event_new()
  3. 將事件添加到事件處理框架event_base上 event_add()
  4. 啟動(dòng)事件循環(huán)檢測(cè) event_base_dispatch()
  5. 循環(huán)結(jié)束之后釋放資源 event_base_free() 、event_free()

處理帶緩沖區(qū)的事件:

1、創(chuàng)建事件處理框架event_base event_base_new()

2、服務(wù)器端:

  1. 創(chuàng)建連接監(jiān)聽(tīng)器(在回調(diào)函數(shù)得到fd) evconnlistener_new_bind()
  2. 將通信fd包裝 bufferevent_socket_new()
  3. 使用bufferevent通信:給bufferevent讀寫(xiě)緩沖區(qū)設(shè)置回調(diào)函數(shù) bufferevent_setcb()
  4. 設(shè)置讀緩沖區(qū)可用 bufferevent_enable()
  5. 對(duì)緩沖區(qū)數(shù)據(jù)操作 bufferevent_write()、bufferevent_rea()

3、客戶(hù)端:

  1. 創(chuàng)建通信用的fd并且使用bufferevent包裝 bufferevent_socket_new()
  2. 連接服務(wù)器 bufferevent_socket_connect()
  3. 使用bufferevent通信:給bufferevent讀寫(xiě)緩沖區(qū)設(shè)置回調(diào)函數(shù) bufferevent_setcb()
  4. 設(shè)置讀緩沖區(qū)可用 bufferevent_enable()
  5. 對(duì)緩沖區(qū)數(shù)據(jù)操作 bufferevent_write()、bufferevent_read()
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7615

    瀏覽量

    137841
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    653

    瀏覽量

    29513
  • 網(wǎng)絡(luò)庫(kù)

    關(guān)注

    0

    文章

    7

    瀏覽量

    1315
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙開(kāi)發(fā)實(shí)戰(zhàn):網(wǎng)絡(luò)請(qǐng)求庫(kù)【axios】

    [Axios]?,是一個(gè)基于 promise 的網(wǎng)絡(luò)請(qǐng)求庫(kù),可以運(yùn)行 node.js 和瀏覽器中。本庫(kù)基于[Axios]原庫(kù)v1.3.4版本進(jìn)行適配,使其可以運(yùn)行在 OpenHarmo
    的頭像 發(fā)表于 03-25 16:47 ?4056次閱讀
    鴻蒙開(kāi)發(fā)實(shí)戰(zhàn):<b class='flag-5'>網(wǎng)絡(luò)</b>請(qǐng)求<b class='flag-5'>庫(kù)</b>【axios】

    安裝libevent報(bào)錯(cuò)

    [dudu@localhost libevent-1.3]# makemakeall-recursivemake[1]: 進(jìn)入目錄“/tmp/libevent-1.3”Making all
    發(fā)表于 07-30 08:22

    Linux經(jīng)典書(shū)籍介紹

    Libevent 是一個(gè)用C語(yǔ)言編寫(xiě)的、輕量級(jí)的開(kāi)源高性能事件通知庫(kù),主要有以下幾個(gè)亮點(diǎn):事件驅(qū)動(dòng)( event-driven),高性能;輕量級(jí),專(zhuān)注于網(wǎng)絡(luò),不如 ACE 那么臃腫龐大;源代碼相當(dāng)
    發(fā)表于 07-26 07:34

    怎樣去移植在ARM嵌入式平臺(tái)的libevent

    libevent-2.1.8-stable.tar.gz 下載openssl-1.1.1a.tar.gz 下載openssl 交叉編譯在《arm-linux 交叉編譯wget支持openssl, 使
    發(fā)表于 12-14 07:15

    如何將交叉編譯libevent源碼移植到RK1126平臺(tái)上

    程序中需要起一個(gè)http服務(wù)來(lái)與主控進(jìn)行交互,正好之前海思平臺(tái)用的是libevent現(xiàn)在需要移植到RK平臺(tái) 。把libevent源碼下下來(lái)之后 隨便放一個(gè)目錄然后建一個(gè)build.sh內(nèi)容如下
    發(fā)表于 10-08 16:40

    Oracle數(shù)據(jù)庫(kù)網(wǎng)絡(luò)安全訪(fǎng)問(wèn)機(jī)制

    本文主要分析了Oracle 客戶(hù)端通過(guò)Net8 訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)服務(wù)器過(guò)程,闡述了Oracle 數(shù)據(jù)庫(kù)網(wǎng)絡(luò)訪(fǎng)問(wèn)機(jī)制以及Net8 在實(shí)現(xiàn)Oracle 數(shù)據(jù)庫(kù)的服務(wù)器和客戶(hù)端之間安全的數(shù)據(jù)通信
    發(fā)表于 08-29 10:20 ?20次下載

    一種網(wǎng)絡(luò)圖像數(shù)據(jù)庫(kù)的快速檢索方法

    一種網(wǎng)絡(luò)圖像數(shù)據(jù)庫(kù)的快速檢索方法:傳統(tǒng)網(wǎng)絡(luò)圖像數(shù)據(jù)庫(kù)的檢索操作,通常是客戶(hù)端直接將待檢索的圖像通過(guò)網(wǎng)絡(luò)傳輸給圖像數(shù)據(jù)
    發(fā)表于 10-26 11:28 ?9次下載

    Java數(shù)據(jù)庫(kù)連接及網(wǎng)絡(luò)程序設(shè)計(jì)

    Java數(shù)據(jù)庫(kù)連接及網(wǎng)絡(luò)程序設(shè)計(jì) 一、實(shí)驗(yàn)?zāi)康模?     通過(guò)Socket編程,掌握網(wǎng)絡(luò)應(yīng)用程序的開(kāi)發(fā)方法;完成數(shù)據(jù)庫(kù)的連接;掌握利用Ja
    發(fā)表于 12-05 23:56 ?1462次閱讀

    Android開(kāi)發(fā)的各大網(wǎng)絡(luò)請(qǐng)求庫(kù)實(shí)際案例

    Android開(kāi)發(fā)的 各大網(wǎng)絡(luò)請(qǐng)求庫(kù)的實(shí)際案例。
    發(fā)表于 09-14 20:21 ?4次下載

    NVIDIA深度神經(jīng)網(wǎng)絡(luò)加速庫(kù)cuDNN軟件安裝教程

    計(jì)基于GPU的加速庫(kù) 。cuDNN為深度神經(jīng)網(wǎng)絡(luò)中的標(biāo)準(zhǔn)流程提供了高度優(yōu)化的實(shí)現(xiàn)方式,例如convolution、pooling、normalization以及activation layers的前向以及后向過(guò)程。 cuDNN只是NVIDIA深度神經(jīng)
    發(fā)表于 12-08 10:40 ?2295次閱讀

    一個(gè)最簡(jiǎn)單的事件驅(qū)動(dòng)的IO libevent編程例子

    本文演示一個(gè)最簡(jiǎn)單的基于libevent編程的例子。libevent是事件驅(qū)動(dòng)的IO,適用于“好萊塢原則”。
    的頭像 發(fā)表于 03-23 09:54 ?6451次閱讀
    一個(gè)最簡(jiǎn)單的事件驅(qū)動(dòng)的IO <b class='flag-5'>libevent</b>編程例子

    OHosAsync底層網(wǎng)絡(luò)協(xié)議庫(kù)的教程案例

    OHosAsync 是一個(gè)底層網(wǎng)絡(luò)協(xié)議庫(kù)。如果您正在尋找一個(gè)易于使用、更高級(jí)別、支持 Ohos 的 http 請(qǐng)求庫(kù),請(qǐng)查看 Ion(它構(gòu)建在 OhosAsync 之上)。典型的 Ohos 應(yīng)用程序
    發(fā)表于 04-12 10:01 ?2次下載

    OHOS庫(kù)反應(yīng)網(wǎng)絡(luò)的使用教程

    ReactiveNetwork :ReactiveNetwork 是一個(gè) OHOS 庫(kù),通過(guò) RxJava Observables 監(jiān)聽(tīng)網(wǎng)絡(luò)連接狀態(tài)和互聯(lián)網(wǎng)連接。它是用反應(yīng)式編程方法編寫(xiě)
    發(fā)表于 04-12 10:11 ?2次下載

    基于ASP和數(shù)據(jù)庫(kù)技術(shù)構(gòu)建的網(wǎng)絡(luò)教學(xué)平臺(tái)

    電子發(fā)燒友網(wǎng)站提供《基于ASP和數(shù)據(jù)庫(kù)技術(shù)構(gòu)建的網(wǎng)絡(luò)教學(xué)平臺(tái).pdf》資料免費(fèi)下載
    發(fā)表于 10-08 11:40 ?0次下載
    基于ASP和數(shù)據(jù)<b class='flag-5'>庫(kù)</b>技術(shù)構(gòu)建的<b class='flag-5'>網(wǎng)絡(luò)</b>教學(xué)平臺(tái)

    Libevent框架庫(kù)簡(jiǎn)介

    一、Libevent簡(jiǎn)介 Libevent是開(kāi)源社區(qū)一款高性能的I/O框架庫(kù),其具有如下特點(diǎn): 1、跨平臺(tái)支持。Libevent支持Linux、UNIX和Windows。 2、統(tǒng)一事件
    的頭像 發(fā)表于 11-09 16:43 ?1255次閱讀
    <b class='flag-5'>Libevent</b>框架<b class='flag-5'>庫(kù)</b>簡(jiǎn)介
    主站蜘蛛池模板: 手机看片国产免费永久 | 国产福利精品视频 | 交在线观看网站视频 | www.色噜噜| 一区不卡视频 | 久久久久国产一级毛片高清版 | 日本黄色免费网站 | 天天都色 | 午夜视频在线观看国产 | 种子天堂bt磁力在线资源 | 五月天欧美| 久久精品国产99精品最新 | 成人最新午夜免费视频 | 亚洲午夜久久久久久噜噜噜 | 五月激情视频 | 夜性影院| 日本老师xxxxxxxxx79 | 操操操干干 | 四虎精品影院在线观看视频 | 美女免费黄 | 色色视频网 | 亚洲婷婷影院 | 激情五月亚洲色图 | 美女和帅哥在床上玩的不可描述 | 久久久久久久网站 | 成人中文字幕一区二区三区 | www日| 日本福利小视频 | 日本不卡高清免费 | 青草午夜精品视频在线观看 | 天天操天天插 | 中文字幕一区二区三区精品 | 性xxxx奶大欧美高清 | 日本美女视频网站 | 国产一区二区三区在线观看视频 | 奇米影视四色首页手机在线 | 国产人成精品香港三级古代 | 爱爱小视频免费看 | 成人三级在线播放线观看 | 中文字幕色婷婷在线精品中 | 在线视频影院 |