一、libevent的使用
首先我们知道,memcached是使用了iblievet作为网络框架的,而iblievet又是单线程模型的基于linux下epoll事件的异步模型。因此,其基本的思想就是 对可读,可写,超时,出错等事件进行绑定函数,等有其事件发生,对其绑定函数回调。
可以减掉了解一下 libevent基本api调用

- struct event_base *base;
- base = event_base_new();//初始化libevent
event_base_new对比epoll,可以理解为epoll里的epoll_create。
event_base内部有一个循环,循环阻塞在epoll调用上,当有一个事件发生的时候,才会去处理这个事件。其中,这个事件是被绑定在event_base上面的,每一个事件就会对应一个struct event,可以是监听的fd。
其中struct event 使用event_new 来创建和绑定,使用event_add来启用,例如:

- struct event *listener_event;
- listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void*)base);
参数说明:
base:event_base类型,event_base_new的返回值
listener:监听的fd,listen的fd
EV_READ|EV_PERSIST:事件的类型及属性
do_accept:绑定的回调函数
(void*)base:给回调函数的参数
event_add(listener_event, NULL);
对比epoll:
event_new相当于epoll中的epoll_wait,其中的epoll里的while循环,在libevent里使用event_base_dispatch。
event_add相当于epoll中的epoll_ctl,参数是EPOLL_CTL_ADD,添加事件。
注:libevent支持的事件及属性包括(使用bitfield实现,所以要用 | 来让它们合体)
EV_TIMEOUT: 超时
EV_READ: 只要网络缓冲中还有数据,回调函数就会被触发
EV_WRITE: 只要塞给网络缓冲的数据被写完,回调函数就会被触发
EV_SIGNAL: POSIX信号量
EV_PERSIST: 不指定这个属性的话,回调函数被触发后事件会被删除
EV_ET: Edge-Trigger边缘触发,相当于EPOLL的ET模式
事件创建添加之后,就可以处理发生的事件了,相当于epoll里的epoll_wait,在libevent里使用event_base_dispatch启动event_base循环,直到不再有需要关注的事件。
有了上面的分析,结合之前做的epoll服务端程序,对于一个服务器程序,流程基本是这样的:
1. 创建socket,bind,listen,设置为非阻塞模式
2. 创建一个event_base,即
- struct event_base * event_base_new(void)
3. 创建一个event,将该socket托管给event_base,指定要监听的事件类型,并绑定上相应的回调函数(及需要给它的参数)。即
- struct event * event_new(struct event_base *base, evutil_socket_t fd, short events, void (*cb)(evutil_socket_t, short, void *), void *arg)
4. 启用该事件,即
- int event_add(struct event *ev, const struct timeval *tv)
5. 进入事件循环,即
- int event_base_dispatch(struct event_base *event_base)
二、memcached源码分析
main函数启动,首先会初始化很多数据,这里我们只涉及大网络这块,其他以后分析,先忽略。 1.首先初始化 主工作线程的的iblievet对象

- /* initialize main thread libevent instance */
- main_base = event_init();
最后会调用

- /* enter the event loop */
- if (event_base_loop(main_base, 0) != 0) {
- retval = EXIT_FAILURE;
- }
在该对象内部循环。不退出。
2.初始化连接的对象

- static void conn_init(void) {
- freetotal = 200;
- freecurr = 0;
- if ((freeconns = calloc(freetotal, sizeof(conn *))) == NULL) {
- fprintf(stderr, "Failed to allocate connection structures\n");
- }
- return;
- }
这里是先预先分配200个conn*的内存。等有连接上来,会从freeconns 取。 如下代码:

- /*
- * Returns a connection from the freelist, if any.
- */
- conn *conn_from_freelist() {
- conn *c;
- pthread_mutex_lock(&conn_lock);
- if (freecurr > 0) {
- c = freeconns[--freecurr];
- } else {
- c = NULL;
- }
- pthread_mutex_unlock(&conn_lock);
- return c;
- }
3.那么conn的结构体内部长什么样子呢?

- typedef struct conn conn;
- struct conn {
- int sfd;
- sasl_conn_t *sasl_conn;
- enum conn_states state;
- enum bin_substates substate;
- struct event event;
- short ev_flags;
- short which; /** which events were just triggered */
- char *rbuf; /** buffer to read commands into */
- char *rcurr; /** but if we parsed some already, this is where we stopped */
- int rsize; /** total allocated size of rbuf */
- int rbytes; /** how much data, starting from rcur, do we have unparsed */
- char *wbuf;
- char *wcurr;
- int wsize;
- int wbytes;
- /** which state to go into after finishing current write */
- enum conn_states write_and_go;
- void *write_and_free; /** free this memory after finishing writing */
- char *ritem; /** when we read in an item's value, it goes here */
- int rlbytes;
- /* data for the nread state */
- /**
- * item is used to hold an item structure created after reading the command
- * line of set/add/replace commands, but before we finished reading the actual
- * data. The data is read into ITEM_data(item) to avoid extra copying.
- */
- void *item; /* for commands set/add/replace */
- /* data for the swallow state */
- int sbytes; /* how many bytes to swallow */
- /* data for the mwrite state */
- struct iovec *iov;
- int iovsize; /* number of elements allocated in iov[] */
- int iovused; /* number of elements used in iov[] */
- struct msghdr *msglist;
- int msgsize; /* number of elements allocated in msglist[] */
- int msgused; /* number of elements used in msglist[] */
- int msgcurr; /* element in msglist[] being transmitted now */
- int msgbytes; /* number of bytes in current msg */
- item **ilist; /* list of items to write out */
- int isize;
- item **icurr;
- int ileft;
- char **suffixlist;
- int suffixsize;
- char **suffixcurr;
- int suffixleft;
- enum protocol protocol; /* which protocol this con<pre name="code" class="cpp"> if (sigignore(SIGPIPE) == -1) {
- perror("failed to ignore SIGPIPE; sigaction");
- exit(EX_OSERR);
- }
nection speaks */ enum network_transport transport; /* what transport is used by this connection */ /* data for UDP clients */ int request_id; /* Incoming UDP request ID, if this is a UDP "connection" */ struct sockaddr request_addr; /* Who sent the most recent request */ socklen_t request_addr_size; unsigned char *hdrbuf; /* udp packet headers */ int hdrsize; /* number of headers' worth of space is allocated */ bool noreply; /* True if the reply should not be sent. */ /* current stats command */ struct { char *buffer; size_t size; size_t offset; } stats; /* Binary protocol stuff */ /* This is where the binary header goes */ protocol_binary_request_header binary_header; uint64_t cas; /* the cas to return */ short cmd; /* current command being processed */ int opaque; int keylen; conn *next; /* Used for generating a list of conn structures */ LIBEVENT_THREAD *thread; /* Pointer to the thread object serving this connection * 上一篇:linux的进程与线程
下一篇:【常用算法思路分析系列】与二分搜索相关高频题
-
如何利用golang运用mysql数据库
这篇文章主要介绍了如何利用golang运用mysql数据库,文章对依赖包、db对象注入ApiRouter等内容,需要的小伙伴可以参考一下
-
shell脚本如何读取properties文件中的值
这篇文章主要给大家介绍了关于shell脚本如何读取properties文件中值的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
-
使用git命令上传代码
这篇文章介绍了使用git命令上传代码的方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
-
Redis之RedisTemplate配置方式(序列和反序列化)
这篇文章主要介绍了Redis之RedisTemplate配置方式(序列和反序列化),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
-
Go语言context上下文管理的使用
本文主要介绍了Go语言context上下文管理的使用,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
- 网页制作模板
- 网页模板免费下载
- asp文件
- oa系统下载
- 站长下载
- html代码大全
- 源代码下载
- 下载网站源码
- 个人网站设计模板
- 网站模板免费下载
- asp下载
- .net源码
- 网页源代码
- 后台管理模板
- 网站源代码下载
- 个人主页源码
- 免费下载
- 网页在线客服代码
- 免费网站模板
- 小偷程序
- 免费代码
- 开源网店
- 中易广告联盟系统
- 网页模板
- 网站源代码
- 个人网页设计模板
- php网页源码
- 模板下载
- 办公管理系统
- 帝国cms
- php源码下载
- 免费企业网站
- 个人网页制作模板
- 即时通讯
- 第三方支付源码
- asp技术
- asp 源码
- cms源码
- yuanma
- php论坛
- 个人网站源码
- 模板网站
- 企业网站管理
- 企业网站程序
- 网站源码下载
- 商业源码
- 企业模板
- 简单网页模板
- 商城系统源码
- 苹果cms10模板