Redis源码整体运行流程详解

本文所引用的源码全部来自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、创建事件循环

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的端口加入到事件监听中,进行监听,由aeCreateFileEvent函数完成,其注册的listen端口可读事件处
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值