Redis Server端处理Client请求的流程图

main函数
main函数主要的功能为:调用initServerConfig函数,进行默认的redisServer数据结构的参数初始化;调用daemonize函数,为服务器开始守护进程,对于守护进行相关详细信息见http://blog.csdn.net/acceptedxukai/article/details/8743189;调用initServer函数,初始化服务器;调用loadServerConfig函数,读取Redis的配置文件,使用配置文件中的参数替换默认的参数值;调用aeMain函数,开启事件循环,整个服务器开始工作。
initServer函数
该函数主要为初始化服务器,需要初始化的内容比较多,主要有:
1、创建事件循环
server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
2、创建TCP与UDP Server,启动服务器,完成bind与listen
/* Open the TCP listening socket for the user commands. */
//server.ipfd是个int数组,启动服务器,完成bind,listen
if (listenToPort(server.port,server.ipfd,&server.ipfd_count) == REDIS_ERR)
exit(1);
/* Open the listening Unix domain socket. */
if (server.unixsocket != NULL) {
unlink(server.unixsocket); /* don't care if this fails */
server.sofd = anetUnixServer(server.neterr,server.unixsocket,server.unixsocketperm);
if (server.sofd == ANET_ERR) {
redisLog(REDIS_WARNING, "Opening socket: %s", server.neterr);
exit(1);
}
}
Redis2.8.2 TCP同时支持IPv4与IPv6,同时与之前版本的Redis不同,此版本支持多个TCP服务器,listenToPort函数主要还是调用anetTcpServer函数,完成socket()-->bind()-->listen(),下面详细查看下TCPServer的创建,UDP直接忽略吧,我也不知道UDP具体用在哪。
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
//绑定bind
if (bind(s,sa,len) == -1) {
anetSetError(err, "bind: %s", strerror(errno));
close(s);
return ANET_ERR;
}
/* Use a backlog of 512 entries. We pass 511 to the listen() call because
* the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
* which will thus give us a backlog of 512 entries */
//监听
if (listen(s, 511) == -1) {
anetSetError(err, "listen: %s", strerror(errno));
close(s);
return ANET_ERR;
}
return ANET_OK;
}
static int _anetTcpServer(char *err, int port, char *bindaddr, int af)
{
int s, rv;
char _port[6]; /* strlen("65535") */
struct addrinfo hints, *servinfo, *p;
snprintf(_port,6,"%d",port);
memset(&hints,0,sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
//套接字地址用于监听绑定
hints.ai_flags = AI_PASSIVE; /* No effect if bindaddr != NULL */
//可以加上hints.ai_protocol = IPPROTO_TCP;
/**getaddrinfo(const char *hostname, const char *servicename,
const struct addrinfo *hint,struct addrinfo **res);
hostname:主机名
servicename: 服务名
hint: 用于过滤的模板,仅能使用ai_family, ai_flags, ai_protocol, ai_socktype,其余字段为0
res:得到所有可用的地址
*/
if ((rv = getaddrinfo(bindaddr,_port,&hints,&servinfo)) != 0) {
anetSetError(err, "%s", gai_strerror(rv));
return ANET_ERR;
}
//轮流尝试多个地址,找到一个允许连接到服务器的地址时便停止
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
continue;
if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error;
//设置套接字选项setsockopt,采用地址复用
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
//bind, listen
if (anetListen(err,s,p->ai_addr,p->ai_addrlen) == ANET_ERR) goto error;
goto end;
}
if (p == NULL) {
anetSetError(err, "unable to bind socket");
goto error;
}
error:
s = ANET_ERR;
end:
freeaddrinfo(servinfo);
return s;
}
//if server.ipfd_count = 0, bindaddr = NULL
int anetTcpServer(char *err, int port, char *bindaddr)
{
return _anetTcpServer(err, port, bindaddr, AF_INET);
}
3、将listen的端口加入到事