前言
在上节中,我们介绍了evbuffers的部分知识,在本小节中,我们将对剩余的部分一起分析总结。
evbuffer_drain
在上节中分析的evbuffer_add_buffer
中,如果添加源缓冲区到目的缓冲区结尾成功,则会调用evbuffer_drain
清除源缓冲区,但是它的功能除了清除整个有效缓冲区以外,还可以清除一部分,接下来我们来看看它的源码:
void
evbuffer_drain(struct evbuffer *buf, size_t len)
{
size_t oldoff = buf->off;
/* 要清除的缓冲区长度大于了有效缓冲区的长度
* 则将有效缓冲区全部清除
* 否则只清除len长度的有效缓冲区
*/
if (len >= buf->off) {
buf->off = 0;
buf->buffer = buf->orig_buffer;
buf->misalign = 0;
/* 难得一见的goto语句
* 但是这里好像可以用if-else替代
*/
goto done;
}
/* 缩小有效缓冲区的大小 */
buf->buffer += len;
buf->misalign += len;
buf->off -= len;
done:
/* Tell someone about changes in this buffer */
/* 随着上面的一顿操作,缓冲区的大小如果已经改变,则回调处理函数 */
if (buf->off != oldoff && buf->cb != NULL)
(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
}
在当时调用evbuffer_add_buffer
时,传递给evbuffer_drain
的len
是等与buf->off
的,所以会清除整个缓冲区的大小,但是其实这个函数的作用是清除指定大小的有效缓冲区。逻辑也很简单:
- len的长度是否大于等于当前有效缓冲区的长度
- 如果大于等于,则清除整个有效缓冲区
- 否则清除指定大小的有效缓冲区(将buffer后移,调整off)
- 如果满足缓冲区大小被改变的条件,则调用回调函数
下面介绍一下evbuffer_remove
,它和evbuffer_drain
关系密切(毕竟里面就调用了evbuffer_drain
),只不过会将该缓冲区指定大小的内容读出来,然后再消除缓冲区。代码如下:
/* Reads data from an event buffer and drains the bytes read */
int
evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
{
size_t nread = datlen;
//这里也是处理了一下指定大小大于有效缓冲区大小的情况
if (nread >= buf->off)
nread = buf->off;
/* 将数据拷贝到data
* 然后清除已读的数据
* 最后返回读取的大小
*/
memcpy(data, buf->buffer, nread);
evbuffer_drain(buf, nread);
return (nread);
}
添加格式化字符串到缓冲区
除了普通的数据,将格式化的字符串添加到缓冲区需要特殊的处理。这部分主要是由evbuffer_add_printf
以及evbuffer_add_vprintf
完成。
int
evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
{
int res = -1;
va_list ap;
va_start(ap, fmt);
res = evbuffer_add_vprintf(buf, fmt, ap); //调用该函数实现
va_end(ap);
return (res);
}
这个函数涉及到C语言中可变参数的用法,具体过程有时间我再整理出来。
里面主要调用的了evbuffer_add_vprintf
函数,代码如下:
int
evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
{
char *buffer;
size_t space;
size_t oldoff =