libevent (带缓冲区的事件)

struct bufferevent

  • 每个bufferevent有两个数据相关的回调
    • 一个读取回调
      • 从底层传输端口读取了任意量的数据之后会调用读取回调(默认)
    • 一个写入回调
      • 输入出缓冲区中足够量的数据被清空到底层传输端口后写入回调会被调用(默认)
  • 【1】创建基于套接字的bufferevent
    • 可以使用bufferevent_socket_new()创建基于套接字bufferevent
      • struct bufferevent* bufferevent_sock_new(
        struct event_base* base,
        evutil_socket_t fd,
        enum bufferevent_options optinos //BEV_OPT_CLOSE_ON_FREE
        );
    • 成功返回要给buffevent,失败则返回NULL
  • 【4】给读写缓冲区设置回调
    • bufferevent_setcb(
      struct bufferevent* bufev,
      bufferevent_data_cb readcb,
      bufferevent_data_cb writecb,
      bufferevent_event_cb eventcb,
      void* cbarg
      );
  • 【3】释放bufferevent操作
    • bufferevent_free(struct bufferevent* bev);
  • 服务端用的函数
    • 创建监听的套接字
    • 绑定
    • 监听
    • 接收连接请求
    • 涵盖了以上的所有操作 struct evconnlistener* evconnlistener_new_bind(
      struct event_base* base,
      evconnlistener_cb cb,
      void* ptr,
      unsigned flags, // LEV_OPT_CLOSE_ON_FREE LEV_OPT_REUSEABLE
      int backlog, // -1:使用默认的最大值
      const struct sockaddr* sa, // 服务器的ip和端口信息
      int socklen
      )
    • 释放 void evconnlistener_free(struct evconnlistener* lev);

服务端代码示例

  #include <stdio.h>                                                                                                        
  #include <unistd.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <string.h>
  #include <event2/event.h>
  #include <event2/listener.h>
  #include <event2/bufferevent.h>

  // 读回调函数
  void read_cb(
               struct bufferevent* bev,
              void* arg
              )
  {
      // 读缓冲区里面的数据
      char buf[1024] = {0};
      bufferevent_read(bev,buf,sizeof(buf));
      printf("recv buf: %s\n",buf);
     char* pt = "你发送的数据我已经收到了...\n";
      // 发送数据,往缓冲区中写数据
      bufferevent_write(bev,pt,strlen(pt)+1);
      printf("我发送了数据,给客户端....\n");
  }
  void write_cb(
               struct bufferevent* bev,
               void* arg
               )
  {
      printf("发送的数据已经被发送出去了\n");
  }
  void event_cb(
                struct bufferevent* bev,
                short events,
               void* arg
               )
  {
      /*
       * EV_EVENT_READING: 读取操作时发生某事件,具体是哪种事件请看其他标志.
       * BEV_EVENT_WRITING: 写入操作时发生某事件,具体是那种事件请看其他标志
       * BEV_EVENT_ERROR: 操作时发生错误,关于错误的更多信息,请调用EVUTIL_SOCKET_ERROR()
       * BEV_EVENT_TIMEOUT: 发生超时
       * BEV_EVENT_EOF: 遇到文件结束指示
       * BEV_EVENT_CONNECTED: 请求的链接过程已经完成
       * */
      if(events & BEV_EVENT_EOF){
          printf("connection closed\n");
      }else if(events & BEV_EVENT_ERROR)
      {
          printf("some other error\n");
      }
      // 释放bufferevent资源
      bufferevent_free(bev);
  }
  // 连接完成之后,对应的通信操作
  void listen_cb(
                struct evconnlistener* listener,
                 evutil_socket_t fd,
                struct sockaddr* addr,
                int len,void* ptr
                )
  {
      printf("connect new client\n");
      // 得到传进来的event_base
      struct event_base* base = (struct event_base*)ptr;
      // 接收和发送数据
      // 将fd封装成bufferevent
      struct bufferevent* bev = NULL;
      bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
      // 给bufferevent对应的读写缓冲区设置回调函数    
      bufferevent_setcb(bev,read_cb,write_cb,event_cb,NULL);
      // 设置读缓冲区的回调可用,默认写是可用的
      bufferevent_enable(bev,EV_READ);
  }
  
 int main(int argc, char *argv[])                                                         
  {
      // init server info
      struct sockaddr_in serv;
      memset(&serv,0,sizeof(serv));
      serv.sin_family = AF_INET;
      serv.sin_port = htons(8765);
      serv.sin_addr.s_addr = htonl(INADDR_ANY);
      // 创建时间处理框架
      struct event_base* base = event_base_new();
      // 创建监听的套接字       
      // 绑定
      // 监听
      // 等待并接受连接
      struct evconnlistener* listen = NULL;
      // 有新链接的时候,listen_cb被调用
      listen = evconnlistener_new_bind(base,listen_cb,base,
                                       LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,-1,
                                       (struct sockaddr*)&serv,sizeof(serv));
      // 开始事件循环
      event_base_dispatch(base);
      // 释放资源
      evconnlistener_free(listen);
      event_base_free(base);
      return 0;
  }   

客户端

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>


void read_cb(struct bufferevent *bev, void *arg)
{
    char buf[1024] = {0}; 
    bufferevent_read(bev, buf, sizeof(buf));
    printf("Server say: %s\n", buf);
}

void write_cb(struct bufferevent *bev, void *arg)
{
    printf("I am Write_cb function....\n");
}

void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
        printf("connection closed\n");  
    }
    else if(events & BEV_EVENT_ERROR)   
    {
        printf("some other error\n");
    }
    else if(events & BEV_EVENT_CONNECTED)
    {
        printf("成功连接到服务器, O(∩_∩)O哈哈~\n");
        return;
    }
    
    bufferevent_free(bev);
    printf("free bufferevent...\n");
}

void send_cb(evutil_socket_t fd, short what, void *arg)
{
    char buf[1024] = {0}; 
    struct bufferevent* bev = (struct bufferevent*)arg;
    printf("请输入要发送的数据: \n");
    read(fd, buf, sizeof(buf));
    bufferevent_write(bev, buf, strlen(buf)+1);
}


int main(int argc, const char* argv[])
{
    struct event_base* base;
    base = event_base_new();


    struct bufferevent* bev;
    bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

    // 连接服务器
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8765);
    inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));

    // 设置回调
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    bufferevent_enable(bev, EV_READ | EV_PERSIST);

    // 创建一个事件
    struct event* ev = event_new(base, STDIN_FILENO, 
                                 EV_READ | EV_PERSIST, 
                                 send_cb, bev);
    event_add(ev, NULL);
    
    event_base_dispatch(base);

    event_base_free(base);

    return 0;
}

posted on 2021-05-11 10:31  lodger47  阅读(231)  评论(0)    收藏  举报

导航