Libevent 的簡單實用

輕量級網絡庫Libevent對高效的I/O進行了封裝,提供統一的API,我們調用API就會很方便,要搞清楚每個API背後的操作。
     什麼是高效的I/O???       
                    如Linux中獨有的epoll,windows的IOCP,BSD的Kqueque

我使用的是libevent2.0.21版本, Libevent2.0版本以後提供了bufferevent 提供了易用的API,bufferevent 解決了粘包等問題,我們在寫程序的時候就不用自己管理緩衝區了。

關於tcp網絡socket編程的一系列流程 可以查看

接下來說libevent的使用教程

  • 第一步
    //創建一個event_base
    struct event_base *base = event_base_new();

     

  • 第二步

    //創建並綁定一個event
    struct event *event_listen = event_new(base, sockfd, EV_READ|EV_PERSIST, CallBack_Func, (void*)base);

     

  • 第三步

    //添加事件
    event_add(even_listen, NULL);

     

  • 第四步 

    //事件循環
    event_base_dispatch(base);

     

  • 第五步   
    1.設置描述符c(accept之後返回的描述符fd)爲​nonblocking
                  Linux中將socket設置爲非阻塞   int flag = fcntl(sockfd, F_GETFL, 0);      fcntl(sockfd, F_SETFL, flag|O_NONBLOCK);
    2.創建一個bufferevent,struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    3.調用bufferevent_setcb(bev, Read_cb, Write_cb, bufferent_event_erro3, NULL);
    4.調用bufferevent_enable(bev, EV_READ | EV_RWRITE | EV_PERSIST);  啓用read/write事件

下邊就是整個服務器調用libevent的代碼編程

//
// Created by yanpan on 2019/4/26.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#include <event.h>
using namespace std;

//#define address 127.0.0.1
//#define port 8888


void OnRead(struct bufferevent *bev, void *arg)
{
    cout<<"bufferent_event_ok happened ....."<<endl;
    evutil_socket_t sfd = bufferevent_getfd(bev);
    int recv_size = 0;
    char buf[100];
    memset(buf,0,sizeof(char)*100);
    std::cout<<"enter buf==="<<buf<<std::endl;
    if ((recv_size = bufferevent_read(bev, buf, 100)) > 0) // 讀取前100位的數據
    {
    }
    std::cout<<"get buf==="<<buf<<std::endl;
    int write_num = bufferevent_write(bev, "ok", 2);
    cout << write_num << " characters written" << endl;
}


void bufferent_event_erro3(struct bufferevent *bev, short event, void *arg)
{
    evutil_socket_t sfd = bufferevent_getfd(bev);
    bufferevent_free(bev);
}

void OnAccept(int sockfd, short iEvent, void *arg)
{
    cout<< "OnAccept happended >>>>> "  <<endl;
    struct sockaddr_in cli;
    socklen_t len = sizeof(cli);
    evutil_socket_t fd = accept(sockfd, (struct sockaddr*)&cli, &len);
    if(-1 == fd)
    {
        cout<< "fd error" <<endl;
        return;
    }
    struct event_base* base = static_cast<event_base*> (arg);

    int flag = EV_READ | EV_PERSIST;
    evutil_make_socket_nonblocking(fd);   //將fd設置成非阻塞
    struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev, OnRead, NULL, bufferent_event_erro3, NULL);
    bufferevent_enable(bev, flag);
}
int main()
{
    int sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd)
        return 0;

    struct sockaddr_in ser;
    ser.sin_family = PF_INET;
    ser.sin_addr.s_addr = inet_addr("127.0.0.1");
    ser.sin_port = htons(8888);

    int ret = bind(sockfd, (struct sockaddr*)&ser, sizeof(ser));
    if(-1 == ret)
        return 0;
    int listenfd = listen(sockfd, 5);
    if(-1 == listenfd)
        return 0;
    //初始化base
    struct event_base* base = event_base_new();

    struct event *even_listen = event_new(base, sockfd, EV_READ|EV_PERSIST, OnAccept, (void*)base);


    //添加事件
    event_add(even_listen, NULL);

    //事件循環
    event_base_dispatch(base);
    return 0;
}

堅持✊

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