美文网首页
Evbuffers:通用缓存IO函数

Evbuffers:通用缓存IO函数

作者: 食梦狸猫 | 来源:发表于2019-03-20 21:58 被阅读0次

    Evbuffer是用来充当缓存网络IO的缓存功能

    创建销毁一个Evbuffer

    struct evbuffer *evbuffer_new(void);
    void evbuffer_free(struct evbuffer *buf);
    
    

    Evbuffer和线程安全

    int evbuffer_enable_locking(struct evbuffer *buf, void *lock);
    void evbuffer_lock(struct evbuffer *buf);
    void evbuffer_unlock(struct evbuffer *buf);
    

    默认情况下,Evbuffer不是线程安全的。如果想让Evbuffer变得线程安全,可以用evbuffer_enable_locking,如果lock为NULL,则自动分配一个新锁。

    size_t evbuffer_get_length(const struct evbuffer *buf);
    
    

    返回存储的字节数

    size_t evbuffer_get_contiguous_space(const struct evbuffer *buf);
    
    

    evbuffer里的字节可能分布在内存中不同的块上,这个函数返回当前存储的第一个连续块上的字节数。

    添加数据到evbuffer

    int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
    

    这个函数添加data里datlen字节的数据到buf的末尾。

    int evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
    int evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap);
    
    int evbuffer_expand(struct evbuffer *buf, size_t datlen);
    

    这个函数将buf的在内存中的最后一个块转换为一个新块,让buf可以包含datlen大小的字节。

    移动data从一个evbuffer到另一个

    int evbuffer_add_buffer(struct evbuffer *dst, struct evbuffer *src);
    int evbuffer_remove_buffer(struct evbuffer *src, struct evbuffer *dst,
        size_t datlen);
    
    

    移动data到另一个evbuffer的首部

    int evbuffer_prepend(struct evbuffer *buf, const void *data, size_t size);
    int evbuffer_prepend_buffer(struct evbuffer *dst, struct evbuffer* src);
    

    对evbuffer内部进行重新布局

    unsigned char *evbuffer_pullup(struct evbuffer *buf, ev_ssize_t size);
    

    这个函数让buf里的前size字节复制或者移动确保他们是连续的线化且在同一个块上。如果size是负数,那这个函数线化整个buf,如果size比buffer还大,那么返回NULL。用很大的size值调用这个函数会执行的很慢。因为会有复制操作

    #include <event2/buffer.h>
    #include <event2/util.h>
    
    #include <string.h>
    
    int parse_socks4(struct evbuffer *buf, ev_uint16_t *port, ev_uint32_t *addr)
    {
        /* Let's parse the start of a SOCKS4 request!  The format is easy:
         * 1 byte of version, 1 byte of command, 2 bytes destport, 4 bytes of
         * destip. */
        unsigned char *mem;
    
        mem = evbuffer_pullup(buf, 8);
    
        if (mem == NULL) {
            /* Not enough data in the buffer */
            return 0;
        } else if (mem[0] != 4 || mem[1] != 1) {
            /* Unrecognized protocol or command */
            return -1;
        } else {
            memcpy(port, mem+2, 2);
            memcpy(addr, mem+4, 4);
            *port = ntohs(*port);
            *addr = ntohl(*addr);
            /* Actually remove the data from the buffer now that we know we
               like it. */
            evbuffer_drain(buf, 8);
            return 1;
        }
    }
    

    从一个evbuffer移动数据

    int evbuffer_drain(struct evbuffer *buf, size_t len);
    int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
    
    

    从一个evbuffer中复制数据

    ev_ssize_t evbuffer_copyout(struct evbuffer *buf, void *data, size_t datlen);
    ev_ssize_t evbuffer_copyout_from(struct evbuffer *buf,
         const struct evbuffer_ptr *pos,
         void *data_out, size_t datlen);
    

    例子:

    #include <event2/buffer.h>
    #include <event2/util.h>
    #include <stdlib.h>
    #include <stdlib.h>
    
    int get_record(struct evbuffer *buf, size_t *size_out, char **record_out)
    {
        /* Let's assume that we're speaking some protocol where records
           contain a 4-byte size field in network order, followed by that
           number of bytes.  We will return 1 and set the 'out' fields if we
           have a whole record, return 0 if the record isn't here yet, and
           -1 on error.  */
        size_t buffer_len = evbuffer_get_length(buf);
        ev_uint32_t record_len;
        char *record;
    
        if (buffer_len < 4)
           return 0; /* The size field hasn't arrived. */
    
       /* We use evbuffer_copyout here so that the size field will stay on
           the buffer for now. */
        evbuffer_copyout(buf, &record_len, 4);
        /* Convert len_buf into host order. */
        record_len = ntohl(record_len);
        if (buffer_len < record_len + 4)
            return 0; /* The record hasn't arrived */
    
        /* Okay, _now_ we can remove the record. */
        record = malloc(record_len);
        if (record == NULL)
            return -1;
    
        evbuffer_drain(buf, 4);
        evbuffer_remove(buf, record, record_len);
    
        *record_out = record;
        *size_out = record_len;
        return 1;
    }
    
    
    

    在一个evbuffer里搜索

    struct evbuffer_ptr {
            ev_ssize_t pos;
            struct {
                    /* internal fields */
            } _internal;
    };
    struct evbuffer_ptr evbuffer_search(struct evbuffer *buffer,
        const char *what, size_t len, const struct evbuffer_ptr *start);
    struct evbuffer_ptr evbuffer_search_range(struct evbuffer *buffer,
        const char *what, size_t len, const struct evbuffer_ptr *start,
        const struct evbuffer_ptr *end);
    struct evbuffer_ptr evbuffer_search_eol(struct evbuffer *buffer,
        struct evbuffer_ptr *start, size_t *eol_len_out,
        enum evbuffer_eol_style eol_style);
    

    例子:

    #include <event2/buffer.h>
    #include <string.h>
    
    /* Count the total occurrences of 'str' in 'buf'. */
    int count_instances(struct evbuffer *buf, const char *str)
    {
        size_t len = strlen(str);
        int total = 0;
        struct evbuffer_ptr p;
    
        if (!len)
            /* Don't try to count the occurrences of a 0-length string. */
            return -1;
    
        evbuffer_ptr_set(buf, &p, 0, EVBUFFER_PTR_SET);
    
        while (1) {
             p = evbuffer_search(buf, str, len, &p);
             if (p.pos < 0)
                 break;
             total++;
             evbuffer_ptr_set(buf, &p, 1, EVBUFFER_PTR_ADD);
        }
    
        return total;
    }
    

    直接添加数据到一个evbuffer

    int evbuffer_reserve_space(struct evbuffer *buf, ev_ssize_t size,
        struct evbuffer_iovec *vec, int n_vecs);
    int evbuffer_commit_space(struct evbuffer *buf,
        struct evbuffer_iovec *vec, int n_vecs);
    

    例子:

    struct evbuffer_iovec v[2];
    int n, i;
    size_t n_to_add = 2048;
    
    /* Reserve 2048 bytes.*/
    n = evbuffer_reserve_space(buf, n_to_add, v, 2);
    if (n<=0)
       return; /* Unable to reserve the space for some reason. */
    
    for (i=0; i<n && n_to_add > 0; ++i) {
       size_t len = v[i].iov_len;
       if (len > n_to_add) /* Don't write more than n_to_add bytes. */
          len = n_to_add;
       if (generate_data(v[i].iov_base, len) < 0) {
          /* If there was a problem during data generation, we can just stop
             here; no data will be committed to the buffer. */
          return;
       }
       /* Set iov_len to the number of bytes we actually wrote, so we
          don't commit too much. */
       v[i].iov_len = len;
    }
    
    /* We commit the space here.  Note that we give it 'i' (the number of
       vectors we actually used) rather than 'n' (the number of vectors we
       had available. */
    if (evbuffer_commit_space(buf, v, i) < 0)
       return; /* Error committing */
    
    

    evbuffer的网络IO

    int evbuffer_write(struct evbuffer *buffer, evutil_socket_t fd);
    int evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
            ev_ssize_t howmuch);
    int evbuffer_read(struct evbuffer *buffer, evutil_socket_t fd, int howmuch);
    

    Evbuffer和回调函数

    struct evbuffer_cb_info {
            size_t orig_size;
            size_t n_added;
            size_t n_deleted;
    };
    
    typedef void (*evbuffer_cb_func)(struct evbuffer *buffer,
        const struct evbuffer_cb_info *info, void *arg);
    struct evbuffer_cb_entry;
    struct evbuffer_cb_entry *evbuffer_add_cb(struct evbuffer *buffer,
        evbuffer_cb_func cb, void *cbarg);
    int evbuffer_remove_cb_entry(struct evbuffer *buffer,
        struct evbuffer_cb_entry *ent);
    int evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb,
        void *cbarg);
    
    #define EVBUFFER_CB_ENABLED 1
    int evbuffer_cb_set_flags(struct evbuffer *buffer,
                              struct evbuffer_cb_entry *cb,
                              ev_uint32_t flags);
    int evbuffer_cb_clear_flags(struct evbuffer *buffer,
                              struct evbuffer_cb_entry *cb,
                              ev_uint32_t flags);
    

    例子:

    #include <event2/buffer.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    /* Here's a callback that remembers how many bytes we have drained in
       total from the buffer, and prints a dot every time we hit a
       megabyte. */
    struct total_processed {
        size_t n;
    };
    void count_megabytes_cb(struct evbuffer *buffer,
        const struct evbuffer_cb_info *info, void *arg)
    {
        struct total_processed *tp = arg;
        size_t old_n = tp->n;
        int megabytes, i;
        tp->n += info->n_deleted;
        megabytes = ((tp->n) >> 20) - (old_n >> 20);
        for (i=0; i<megabytes; ++i)
            putc('.', stdout);
    }
    
    void operation_with_counted_bytes(void)
    {
        struct total_processed *tp = malloc(sizeof(*tp));
        struct evbuffer *buf = evbuffer_new();
        tp->n = 0;
        evbuffer_add_cb(buf, count_megabytes_cb, tp);
    
        /* Use the evbuffer for a while.  When we're done: */
        evbuffer_free(buf);
        free(tp);
    }
    
    

    避免evbufferIO中的数据复制

    typedef void (*evbuffer_ref_cleanup_cb)(const void *data,
        size_t datalen, void *extra);
    
    int evbuffer_add_reference(struct evbuffer *outbuf,
        const void *data, size_t datlen,
        evbuffer_ref_cleanup_cb cleanupfn, void *extra);
    

    例子:

    #include <event2/buffer.h>
    #include <stdlib.h>
    #include <string.h>
    
    /* In this example, we have a bunch of evbuffers that we want to use to
       spool a one-megabyte resource out to the network.  We do this
       without keeping any more copies of the resource in memory than
       necessary. */
    
    #define HUGE_RESOURCE_SIZE (1024*1024)
    struct huge_resource {
        /* We keep a count of the references that exist to this structure,
           so that we know when we can free it. */
        int reference_count;
        char data[HUGE_RESOURCE_SIZE];
    };
    
    struct huge_resource *new_resource(void) {
        struct huge_resource *hr = malloc(sizeof(struct huge_resource));
        hr->reference_count = 1;
        /* Here we should fill hr->data with something.  In real life,
           we'd probably load something or do a complex calculation.
           Here, we'll just fill it with EEs. */
        memset(hr->data, 0xEE, sizeof(hr->data));
        return hr;
    }
    
    void free_resource(struct huge_resource *hr) {
        --hr->reference_count;
        if (hr->reference_count == 0)
            free(hr);
    }
    
    static void cleanup(const void *data, size_t len, void *arg) {
        free_resource(arg);
    }
    
    /* This is the function that actually adds the resource to the
       buffer. */
    void spool_resource_to_evbuffer(struct evbuffer *buf,
        struct huge_resource *hr)
    {
        ++hr->reference_count;
        evbuffer_add_reference(buf, hr->data, HUGE_RESOURCE_SIZE,
            cleanup, hr);
    }
    

    将文件添加到evbuffer中

    int evbuffer_add_file(struct evbuffer *output, int fd, ev_off_t offset,
        size_t length);
    

    相关文章

      网友评论

          本文标题:Evbuffers:通用缓存IO函数

          本文链接:https://www.haomeiwen.com/subject/aikxvqtx.html