本文所引用的源码全部来自Redis2.8.2版本。
Redis源码整体运行流程的相关文件是:redis.h, redis.c, networking.c, ae.h, ae.c。
转载请注明,本文出自:http://blog.csdn.net/acceptedxukai/article/details/17842119
Redis Server端处理Client请求的流程图
main函数
main函数主要的功能为:调用initServerConfig函数,进行默认的redisServer数据结构的参数初始化;调用daemonize函数,为服务器开始守护进程,对于守护进行相关详细信息见http://blog.csdn.net/acceptedxukai/article/details/8743189;调用initServer函数,初始化服务器;调用loadServerConfig函数,读取Redis的配置文件,使用配置文件中的参数替换默认的参数值;调用aeMain函数,开启事件循环,整个服务器开始工作。
initServer函数
该函数主要为初始化服务器,需要初始化的内容比较多,主要有:
1、创建事件循环
2、创建TCP与UDP Server,启动服务器,完成bind与listenserver.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
Redis2.8.2 TCP同时支持IPv4与IPv6,同时与之前版本的Redis不同,此版本支持多个TCP服务器,listenToPort函数主要还是调用anetTcpServer函数,完成socket()-->bind()-->listen(),下面详细查看下TCPServer的创建,UDP直接忽略吧,我也不知道UDP具体用在哪。/* 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); } }
3、将listen的端口加入到事件监听中,进行监听,由aeCreateFileEvent函数完成,其注册的listen端口可读事件处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); }
Redis源码整体运行流程详解
最新推荐文章于 2024-08-22 10:22:39 发布
本文详细介绍了Redis服务器从启动到处理客户端请求的整体流程,包括main函数、initServer、acceptTcpHandler、createClient、readQueryFromClient、processCommand与call函数以及sendReplyToClient。通过分析源码,揭示了Redis如何初始化、监听客户端连接、读取请求、执行命令和返回结果。对于想要深入理解Redis运行机制和学习Linux socket编程的读者,这是一个很好的参考。
摘要由CSDN通过智能技术生成