libevent -bufferevent

bufferevent   是在libevent 的reactor的模式里存在的Proactor模式,在event的基础上维护了自己的一个buffer ,我们不再关心数据的读写实际的操作,bufferevent自己实现了缓冲的绑定,当有读数据就绪时,就调用buffer_read 读走数据,或者调用buffer_write 写入给定数据,当出现错误,buffevent有自己的错误处理机制,达到了异步I/O

struct bufferevent 
{
    struct event_base *ev_base;

    struct event ev_read;
    struct event ev_write;

    struct evbuffer *input;//接收数据缓冲
    struct evbuffer *output;//发送数据缓冲

    struct event_watermark wm_read;
    struct event_watermark wm_write;

    evbuffercb readcb;//读回调函数指针
    evbuffercb writecb;//写回调函数指针
    everrorcb errorcb;//错误回调函数指针
    void *cbarg;

    int timeout_read;   /* in seconds */
    int timeout_write;  /* in seconds */

    short enabled;  /* events that are currently enabled */
};

可以看出buffevent 内置了两个event (ev_read,ev_write),当有数据被读入input时,readcb被调用,当ouuput 完成时,writecb被调用,出现网络I/O错误时,errorcb 被调用

buffevent 的使用流程:

  1. 设置sock为非阻塞
    evutil_make_socket_nonblocking(fd);
  2. 使用bufferevent_socket_new创建一个structbufferevent *bev,关联该sockfd,托管给event_base
    struct bufferevent * bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,  int options)
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  3. 设置读/写的回调函数
    void bufferevent_setcb(struct bufferevent *bufev,
        bufferevent_data_cb readcb, bufferevent_data_cb writecb,
        bufferevent_event_cb eventcb, void *cbarg)
    eg.  bufferevent_setcb(bev, readcb, NULL, errorcb, NULL);
  4. 设置事件类型
    int bufferevent_enable(struct bufferevent *bufev, short event)
    eg.  bufferevent_enable(bev, EV_READ|EV_WRITE);
  5.  进入bufferevent_setcb回调函数:在readcb里面从input中读取数据,处理完毕后填充到output中;
  6. writecb对于服务端程序,只需要readcb就可以了,可以置为NULL;

    errorcb用于处理一些错误信息。

例子:简单的服务器

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h>
#include<event2/buffer.h>
#include<event2/bufferevent.h>
void errorcb(struct bufferevent *bev, short error, void *ctx);
int  Listener()
{
  int listener=socket(AF_INET,SOCK_STREAM,0);
  if(listener==-1)
  {
    return -1;
  }
  struct sockaddr_in saddr; 
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons(8000);
  saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
  int res=bind(listener,(struct sockaddr *)&saddr,sizeof(saddr));
  if(res==-1)
  {
    return -1;
  }
   listen(listener,5);
   return listener;
}
void readcb(struct bufferevent* bf,void *ct)
{

  char buff[1024];
  int len=bufferevent_read(bf,buff,1023);
  printf("%s\n",buff);
  char *p = "Hi Client, Server received data succeed";
  bufferevent_write(bf, p, strlen(p)+1);
}
void writecd(struct bufferevent * bev,void *ctx)
{
  printf("succed\n");
}
void do_accept(int fd,short ev,void*arg)
{
  struct event_base * base=(struct event_base*)arg;
  struct sockaddr_in caddr;
  socklen_t len = sizeof(caddr);
  int c=accept(fd,(struct sockaddr*)&caddr,&len);
  evutil_make_socket_nonblocking(c);
  if(c<0)
  {
    perror("accept error");
  }
  else if(c>FD_SETSIZE)
  {
    close(c);
  }
  else 
  {
    //使用bufferevent_socket_new创建一个struct bufferevent *bev,关联该sockfd,托管给event_base
    ////BEV_OPT_CLOSE_ON_FREE表示释放bufferevent时关闭底层传输端口。这将关闭底层套接字,释放底层bufferevent等。
    
    struct bufferevent *bf=bufferevent_socket_new(base,c,BEV_OPT_CLOSE_ON_FREE);
    //设置读写对应的回调函数
    bufferevent_setcb(bf,readcb,writecd,errorcb,NULL);
    //启用读写事件,其实是调用了event_add将相应读写事件加入事件监听队列poll,如果相应事件不置为true,bufferevent 是不会读写数据的。

    bufferevent_enable(bf,EV_READ|EV_WRITE);
  }
}
void errorcb(struct bufferevent *bev, short error, void *ctx)
{
    if (error & BEV_EVENT_EOF)
    {
        /* connection has been closed, do any clean up here */
        printf("connection closed\n");
    }
   else if (error & BEV_EVENT_ERROR)
    {
        /* check errno to see what error occurred */
        printf("some other error\n");
    }
    else if (error & BEV_EVENT_TIMEOUT)
    {
        /* must be a timeout event handle, handle it */
        printf("Timed out\n");
    }
    bufferevent_free(bev);
}
int main()
{
  int listener=Listener();
  assert(listener!=-1);
  struct event_base * base =event_base_new();
  assert(base!=NULL);
  struct event * listen_ev=event_new(base,listener,EV_READ|EV_PERSIST,do_accept,(void*)base);
  event_add(listen_ev,NULL);
  event_base_dispatch(base);
  event_base_free(base);
}

猜你喜欢

转载自www.cnblogs.com/lc-bk/p/12389943.html