libevent Note 4: Filter_bufferevent filter

Filter_bufferevent is based bufferevent filter, which itself is a bufferevent. The data in the cache can be input for the underlying bufferevent operation (encryption / decryption, etc.) and then read the same data can be written to the output buffer bufferevent underlying region after a certain operation. Note that, after creating Filter_bufferevent, the underlying bufferevent read and write callback function will not take effect, while the callback function cache is still valid.

Filter_bufferevent correlation function

bufferevent struct bufferevent_filter_new (struct bufferevent underlying, bufferevent_filter_cb input_filter, bufferevent_filter_cb output_filter, int Options, void ( free_context) (void ), void * ctx): create a filter parameter list as follows:

  • struct bufferevent * underlying: the need to filter the underlying bufferevent;
  • bufferevent_filter_cb input_filter / bufferevent_filter_cb output_filter: bufferevent underlying input / output buffer in the filter operation function, which is triggered when the two filter function data at the source region of the buffer;
  • int option: Set on bufferevent of;
  • void ( free_context) (void ): function called when released, the list of parameters and return values are empty;
  • void * ctx: filter parameters passed to the function;

enum bufferevent_filter_result typedef (* bufferevent_filter_cb) (struct evbuffer the src, struct evbuffer DST, ev_ssize_t dst_limit, enum bufferevent_flush_mode MODE, void * CTX): need to customize, and transmitted to the bufferevent_filter_new () filter function, the following parameter list:

  • struct evbuffer * src: the source of the data buffer to be processed, i.e., taking data from the need to filter this cache;
  • struct evbuffer * dst: The purpose of the buffer zone need to deal with data, data to be processed into the cache;
  • ev_ssize_t dst_limit: length of the filter may be destination buffer ignores this parameter;
  • enum bufferevent_flush_mode mode: filtration mode, to tell the filter what data is due into the filter.
  • void * ctx: function on a given parameter;
  • typedef enum bufferevent_filter_result: filtering function return value, comprising: BEV_OK (normal); BEV_NEED_MORE (need to continue reading data); BEV_ERROR (error);

Filter source / destination buffer

Filter function parameter list contains the filter source / destination buffer. For the input / output filter, the source / destination buffer are different, which is essential for understanding the filter. Can be used for some simple program to determine a relationship parameter and the underlying bufferevent Filter_bufferevent of the filter, the client and server data occurs normally connected, and the server creates a Filter_bufferevent total of four buffers, the filter output is the source of two bufferevent / address of the destination buffer area.

  • Client:
#include <stdio.h>
#include <signal.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(buf);
}
 
void write_cb(struct bufferevent *bev, void *arg)
{
   printf("我是写缓冲区的回调函数...您已发送\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("服务器已连接\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;
    read(fd, buf, sizeof(buf));
    bufferevent_write(bev, buf, strlen(buf)-1);
}
 
void signal_cb(evutil_socket_t sig, short events, void *user_data)
{
    struct event_base *base = user_data;
    struct timeval delay = { 2, 0 };
    printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
    event_base_loopexit(base, &delay);
}

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(9995);
    evutil_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, NULL, 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);

    //for Ctrl+C
    struct event *signal_event;
    signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
    event_add(signal_event, NULL);
    event_add(ev, NULL);  
    event_base_dispatch(base);
    event_base_free(base);
    return 0;
}
  • Server:
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <arpa/inet.h>// interner address
#include <unistd.h>//os
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <event2/listener.h>
#include <sys/types.h>
#include <errno.h>

enum bufferevent_filter_result input_cb(struct evbuffer *src, struct evbuffer *dst, 
        ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx)
{
   //输出缓存区的地址
   printf("the src and dst in fun input_cb: %ld, %ld\n", src, dst);
   //清空源缓存区,避免被一直调用
   evbuffer_drain(src, 1024);
   return BEV_OK;   
}

enum bufferevent_filter_result output_cb(struct evbuffer *src, struct evbuffer *dst,
                ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx)
{
   //输出缓存区的地址
   printf("the src and dst in fun output_cb: %ld, %ld\n", src, dst);
   //清空源缓存区,避免被一直调用
   evbuffer_drain(src, 1024);
   return BEV_OK;
}


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

void write_cb(struct bufferevnet *bev, void *arg)
{
   printf("write_cb\n"); 
}

void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
         struct sockaddr *addr, int len, void *ptr)
{
   struct sockaddr_in *caddr = (struct sockaddr_in *)addr;
   struct event_base *base = (struct event_base *)ptr;
   
   //init bufferevent
   struct bufferevent *bev;
   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
   
   bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
   bufferevent_enable(bev, EV_WRITE | EV_READ);
   //bufferevent_write(bev, "Hello client!", strlen("Hello client!")+1);
   
   struct bufferevent *filter_bev = bufferevent_filter_new(bev, input_cb, output_cb, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
   //设置Filter_bufferevent的读写函数
   bufferevent_setcb(filter_bev, read_cb, write_cb, NULL, NULL);
   bufferevent_enable(filter_bev, EV_READ|EV_WRITE);
   //输出底层bufferevent的缓存区地址
   printf("the input evbuffer and output evbuffer of underlying bufferevent: %ld, %ld\n", bufferevent_get_input(bev), bufferevent_get_output(bev));
   //输出Filter_bufferevent的缓存区地址
   printf("the input evbuffer and output evbuffer of filter bufferevent: %ld, %ld\n", bufferevent_get_input(filter_bev), bufferevent_get_output(filter_bev));
   //先Filter_bufferevent写
   bufferevent_write(filter_bev, "abc", sizeof("abc"));
}


int main(int argc, const char *argv[])
{
   //init server
   struct sockaddr_in servaddr;
   memset(&servaddr, 0, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(9995);
   servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

   //init event_base
   struct event_base *base;
   base = event_base_new();

   //init linstener
   struct evconnlistener *listener;
   listener = evconnlistener_new_bind(base, listener_cb, base, 
           LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE_PORT, 36, 
           (struct socketaddr *)&servaddr, sizeof(servaddr));
   event_base_dispatch(base);

   evconnlistener_free(listener);
   event_base_free(base);
}

The server runs the results:

sunminming@sunminming:~/libevent/filter$ ./addrdemo 
the input evbuffer and output evbuffer of underlying bufferevent: 94493149330208, 94493149330352
the input evbuffer and output evbuffer of filter bufferevent: 94493149331184, 94493149331328
the src and dst in fun output_cb: 94493149331328, 94493149330352
the src and dst in fun input_cb: 94493149330208, 94493149331184

It can be seen:

  • Consistent input buffer address entered in the filter buffer with the underlying source buferevent consistent input buffer and the buffer address of the destination of Filter_bufferevent.
  • Address coincidence output buffer in the output of the filter and the source buffer Filter_bufferevent consistent output buffer address for the destination buffer and the underlying bufferevent.
    Thus, the relationship between four buffers with two filter functions may be drawn to the following:

Demo

After the filter is normally used Demo: input filters the received data will be the underlying process bufferevent plus 1, while the data output of the output filter will be at the end of a copy of the original data is applied.

  • Server:
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <event2/buffer.h>
#include <arpa/inet.h>// interner address
#include <unistd.h>//os
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <event2/listener.h>
#include <sys/types.h>
#include <errno.h>

enum bufferevent_filter_result input_cb(struct evbuffer *src, struct evbuffer *dst, 
        ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx)
{
   //处理输入的数据:从源缓存区读,并加1后放入目的缓存区
   char buf[1024];
   memset(buf, '\0', sizeof(buf));
   evbuffer_remove(src, buf, sizeof(buf));
   int len = strlen(buf);
   printf("%d", len);
   for(int i = 0; i < len; ++i)
   {
      ++buf[i];
   }
   buf[2*len] = '\n';
   evbuffer_add(dst, buf, len);
   return BEV_OK;   
}

enum bufferevent_filter_result output_cb(struct evbuffer *src, struct evbuffer *dst,
                ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx)
{
   //处理输出的数据:从源缓存区读,复制后放入目的缓存区
   char buf[1024] = {0};
   memset(buf, '\0', sizeof(buf));
   evbuffer_remove(src, buf, sizeof(buf));
   int len = strlen(buf);
   for(int i = len; i < 2*len; ++i)
   {
      buf[i] = buf[i - len];
   }
   evbuffer_add(dst, buf, 2*len);
   return BEV_OK;
}


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

void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
         struct sockaddr *addr, int len, void *ptr)
{
   struct sockaddr_in *caddr = (struct sockaddr_in *)addr;
   struct event_base *base = (struct event_base *)ptr;
   
   //init bufferevent
   struct bufferevent *bev;
   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
   
   bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
   bufferevent_enable(bev, EV_WRITE | EV_READ);
   
   struct bufferevent *filter_bev = bufferevent_filter_new(bev, input_cb, output_cb, BEV_OPT_CLOSE_ON_FREE, NULL, NULL);
   bufferevent_setcb(filter_bev, read_cb, NULL, NULL, NULL);
   bufferevent_enable(filter_bev, EV_READ|EV_WRITE);

   bufferevent_write(filter_bev, "abc", sizeof("abc"));
}


int main(int argc, const char *argv[])
{
   //init server
   struct sockaddr_in servaddr;
   memset(&servaddr, 0, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(9995);
   servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

   //init event_base
   struct event_base *base;
   base = event_base_new();

   //init linstener
   struct evconnlistener *listener;
   listener = evconnlistener_new_bind(base, listener_cb, base, 
           LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE_PORT, 36, 
           (struct socketaddr *)&servaddr, sizeof(servaddr));
   event_base_dispatch(base);

   evconnlistener_free(listener);
   event_base_free(base);
}

Client and on a same. See note process.

Guess you like

Origin www.cnblogs.com/sunminming/p/12004089.html