关于接收监听并建立连接得到通讯套接字过程请参考Libevent监听事件的建立过程文档。
涉及到的几个结构体
struct bufferevent_private
{
//主要的结构体
structbufferevent bev;
structevbuffer_cb_entry *read_watermarks_cb;
unsignedown_lock : 1;
//为简化省略了一些变量声明
struct bufferevent_rate_limit*rate_limiting;
};
struct event_watermark
{
size_t low;
size_t high;
};
struct bufferevent
{
structevent_base *ev_base;
const struct bufferevent_ops *be_ops;
struct event ev_read;
struct event ev_write;
structevbuffer *input;
structevbuffer *output;
structevent_watermark wm_read;
structevent_watermark wm_write;
//回调函数
bufferevent_data_cb readcb;
bufferevent_data_cb writecb;
bufferevent_event_cb errorcb;
//回调参数
void*cbarg;
structtimeval timeout_read;
structtimeval timeout_write;
//事件类型
shortenabled;
};
在监听回调事件中代码如下:
static voidlistener_cb(struct evconnlistener *listener,evutil_socket_t fd,struct sockaddr *sa, int socklen, void*user_data)
{
structevent_base *base = (struct event_base*)user_data;
structbufferevent *bev;
bev = bufferevent_socket_new(base, fd,BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, conn_readcb,conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev,EV_WRITE|EV_READ);
}
1.先来看看bufferevent_socket_new函数。
struct bufferevent *
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,int options)
{
//创建bufferevent_private结构体
// bufferevent_init_common对该结构体进行参数初始化,在该函数中,
// 通过bufev->input= evbuffer_new()语句新建evbuffer并赋值。
//传递函数指针struct bufferevent_ops 给bufferevent
bufferevent_init_common(bufev_p, base,&bufferevent_ops_socket,options)
//对bufferevent中的读写事件赋值
event_assign(&bufev->ev_read,bufev->ev_base, fd,EV_READ|EV_PERSIST, bufferevent_readcb, bufev);
event_assign(&bufev->ev_write,bufev->ev_base, fd,EV_WRITE|EV_PERSIST, bufferevent_writecb, bufev);
//设置输入输出缓冲的释放顺序标志
//将buffevevent返回
}
2. bufferevent_setcb(bev, conn_readcb,conn_writecb, conn_eventcb, NULL);
将回调函数设置到bufferevent结构体上。内部进行了线程保护。
3.bufferevent_enable(bev, EV_WRITE|EV_READ)
调用指针结构体的be_socket_enable(struct bufferevent *bufev, shortevent)
该函数内部又调用be_socket_add(&bufev->ev_read,&bufev->timeout_read)
该函数内部又调用event_add(ev,NULL);
该函数内部又调用event_add_internal(ev,tv, 0);
最后将该事件增加到eventBase的哈希表中,并增加到底层监听结构里。
注意读写事件时分别增加的事件,所以一个fd如果要支持读和写的功能,需要增加2个事件。
4. 回调处理
在event_assign函数中读回调用的是bufferevent_readcb,因此当读事件发生时,调用的是bufferevent_readcb函数。
在该函数中
//获取最大可以读取的字节数
readmax =_bufferevent_get_read_max(bufev_p);
//读取数据
res =evbuffer_read(input, fd, (int)howmuch);
//调用用户回调函数
_bufferevent_run_readcb(bufev);
//调用回调
bufev->readcb(bufev,bufev->cbarg);
5.读取过程
struct evbuffer *input =bufferevent_get_input(bev);
memset(buf,0,sizeof(buf));
sz=evbuffer_get_length(input);
if (sz> 0)
{
bufferevent_read(bev,buf,sz);
}