监听和接收
1 创建监听的socket
调用anetTcpServer函数完成,在这个函数中,
A 通过anetCreateSocket创建一个socket , 并设置so_reuseaddr
B 设置需要绑定的地址和端口
C 调用anetListen 进行地址的绑定并且开始监听
2 socket 放入epoll 监听事件
这个通过调用aeCreateFileEvent 函数来实现的,这里需要传递监听的socket, 监听的事件(可读、可写),事件发生后的处理函数。
下面详细介绍下:
A 根据socket ,我们得到文件事件fileEvent
B 调用aeApiAddEvent把socket 放入epoll中
1 根据fileevent 的mask ,来决定是进行add 还是mod操作
2 当前mask 和fileevent中得mask 进行合并
3 根据mask 类型,来设置epoll中监听事件的类型
4 调用epoll_ctl 添加或者修改事件
C 设置事件发生后,对应的处理函数,以及clientData
通过上面的处理,当epoll中事件发生的时候,可以根据事件的类型,分别调用不同的处理函数。
3 在2中设置了listen socket 处理函数是 acceptTcpHandler(src/networking.c) ,我们看看这个函数
这个函数主要调用两个函数
A anetTcpAccept 来完成接收操作
B aceptCommonHandler
1 创建一个客户端的链接,通过调用createClient(src/networking.c)函数来实现。
在这个函数中,主要创建一个链接对象,并把对应的socket 通过aeCreateFileEvent 函数放入epoll , 在这里设置的可读时候处理函数为
readQueryFromClient
还有就是通过调用listAddNodeTail把这个链接放到server.clients的末尾
2 校验下client 数目是不是超过了系统的设置。
处理请求:
从上面的分析,我们知道了,请求进来的入口函数是readQueryFromClient函数:
1 通过read函数,读取请求的数据,并放入到 connect->querybuf 中
2 调用processInputBuffer
这里的querybuf 数据是如下格式:
参数个数 第一个参数长度 第一个参数 第二个参数长度 第二个参数 第三个参数长度 第三个参数 。。。。。。。
首先会通过第一个参数,调用lookupCommand 来查找对应的cmd,
接着调用call函数,以cmd为参数,在call函数中,调用cmd的proc函数.\
那么lookupCommand 是什么东西,它是如何工作的呢?
1 initServerConf 函数中,我们可以看到这个:
server.commands =dictCreate(&commandTableDictType,NULL);
也就是一个dict(两个hash)
2 这个里面放了哪些东西?
在redis.c文件中有一个函数是populateCommandTable,这个函数就是往dict中插入指令,这些指令是在readonlyCommandTable中获取的,那么就赖看看这个:
在redis.c 71行,很长,就不在这里贴了,注意这个结构的第二个成员是处理函数(cmd->proc) ,这个就是最后调用的函数,这下把真个逻辑理清了。