Libevent参考手册第七章:Evbuffers用于缓冲IO的实用工具

当自己看别人翻译过来的图书时,我们有时会经常骂骂咧咧道:“翻译真烂”!可是当我自己尝试去翻译这篇文档时,才知道翻译真的不是一种简单的事情。翻译的不好,所以敬请读者见谅,如果在哪看到比这篇翻译的更好的,敬请告知!谢谢!

Libevent参考手册第七章:Evbuffers:用于缓冲IO的实用工具

Nick Mathewson 

老衣           翻译

Libeventevbuffer功能通过实现一个字节队列,在队列末尾添加数据,在队列头移除数据。

Evbuffers 是通常用来做缓冲网络 IO "缓冲区"部分。他们将不会提供安排 IO IO准备就绪时的触发等功能: 而这些功能是bufferevents应该做的。

本章中的函数声明都在event2/buffer.h 中,除非另有说明。

创建或释放 evbuffer

接口

struct evbuffer *evbuffer_new(void);

void evbuffer_free(struct evbuffer *buf);

这些函数应该是比较清晰: evbuffer_new() 分配并返回一个新的空的 evbuffer evbuffer_free() 函数删除所有的内容。

这些函数从Libevent 0.8版本开始存在。     

Evbuffers 和线程安全

接口

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,则 Libevent 通过evthread_set_lock_creation_callback函数分配一把新锁。否则,它所使用的参数作为该锁。

Evbuffer_lock() evbuffer_unlock() 函数的功能分别是获得或者释放evbuffer 上的锁。您可以使用它们进行一组原子操作。如果evbuffer上没有使用锁,这些函数什么也不做。

(请注意您不需要调用 evbuffer_lock() evbuffer_unlock() 在单个操作上: 单个操作已经是原子操作了。当你有一个以上的操作需要执行时,你只需手动锁定 evbuffer,而不需要引入另一个线程。)

这些函数在Libevent 2.0.1-alpha版本中引入。

检查 evbuffer

接口

size_t evbuffer_get_length(const struct evbuffer *buf);

此函数返回存储在 evbuffer 中的字节的数。

它是在Libevent 2.0.1-alpha版本中引入。

接口

size_t evbuffer_get_contiguous_space(const struct evbuffer *buf);

此函数返回evbuffer的前面的连续存储的字节数。在 evbuffer 中的字节可能存储在多个单独的大块的内存 ;此函数返回第一个文本块中当前存储的字节的数。

它是在Libevent 2.0.1-alpha版本中引入。

将数据添加到 evbuffer 基础知识

接口

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

此函数把存储在data中的datlen个字节的数据追加到buf上,成功返回0,失败返回-1

接口

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

这些函数把格式化得数据追加到buf末尾。处理格式参数和其他余下的参数与C 库中"printf""vprintf"函数相似。这些函数将返回附加的字节的数。

接口

int evbuffer_expand(struct evbuffer *buf, size_t datlen);

此函数改变内存缓冲区中的最后一个区块,或添加新的区块,以致现在的缓冲区足够大能够容纳 datlen个字节无需再次进行分配。

示例

/* Here are two ways to add "Hello world 2.0.1" to a buffer. */
/* Directly: */
evbuffer_add(buf, "Hello world 2.0.1", 17);
 
/* Via printf: */
evbuffer_add_printf(buf, "Hello %s %d.%d.%d", "world", 2, 0, 1);

Evbuffer_add() evbuffer_add_printf() 函数在 Libevent 0.8中引入的。evbuffer_expand() 是在 0.9 evbuffer_add_printf() 首次出现在 Libevent 1.1

将数据从一个 evbuffer 移动到另一个

为了提高效率,Libevent 已经优化了用于将数据从一个 evbuffer 移动到另一个evbuffer的函数。

接口

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

Evbuffer_add_buffer() 函数将从src的所有的数据移动到dst的尾端。成功返回0失败则返回-1

Dst,复制尽可能少的末尾,evbuffer_remove_buffer() 函数移动srcdatlen字节的数据到Dst的末尾,尽量少复制。它返回移动的字节的数。

我们推出了 Libevent 0.8版本中引入evbuffer_add_buffer()函数evbuffer_remove_buffer() Libevent 2.0.1-alpha 中的新功能。

将数据添加到前面的 evbuffer

接口

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

这些功能的工作方式同evbuffer_add() evbuffer_add_buffer() 一样,只是他们将数据移动到目标缓冲区的前面

应谨慎使用这些函数,决不与一bufferevent共享一evbuffer。他们是 Libevent 2.0.1-alpha 中的新功能。

重新排列 evbuffer 的内部的布局

有时你想偷看 evbufferN个字节的数据,并将其视为连续的字节数组。为此,您必须首先确保前面的缓冲区真的连续。

接口

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

evbuffer_pullup() 函数"线性化"buf的前size个字节,复制或移动它们,以确保它们都连续和占用的内存的同一块。如果参数size为负数,则函数 “线性化” 整个缓冲区。如果参数size大于缓冲区中的字节数,则此函数返回 NULL。否则,evbuffer_pullup() 返回 buf 中第一个字节的指针。

,若参数size比较大,调用 evbuffer_pullup()的运行速度可能会较慢,因为它可能需要将整个缓冲区的内容复制。

示例

#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_pullup() 中的参数size等于evbuffer_get_contiguous_space() 所返回的值,则调用evbuffer_pullup()函数不会导致任何数据被复制或者移动。

Evbuffer_pullup()

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值