Redis源码学习-8-Redis源码网络部分简要分析

main函数流程

文章目录

  • main函数流程
    • 0. 前言
    • 1. 简要源码分析
    • 1.1 小结

0. 前言

接下来,我们就跟随一下代码,或者说函数调用栈,来看下。Redis是怎么做的。

1. 简要源码分析

当前,我们先刨除一些业务上的代码,仅仅只看有关网络的代码。

// redis.c

int main(int argc, char **argv) {
     

    // 初始化服务器
    // 这里主要设置就是服务器的一些参数,可以不关心
    initServerConfig();
    
    // 将服务器设置为守护进程
    if (server.daemonize) daemonize();

    // 创建并初始化服务器数据结构
    initServer();
    ...
}
// initServer
void initServer() {
     

    // 初始化EventLoop
    server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
    // 初始化大哈希表
    server.db = zmalloc(sizeof(redisDb)*server.dbnum);
    // 打开 TCP 监听端口,用于等待客户端的命令请求
    if (server.port != 0 &&
        listenToPort(server.port,server.ipfd,&server.ipfd_count) == REDIS_ERR)
        exit(1);
        
    // 为 TCP 连接关联连接应答(accept)处理器
    // 用于接受并应答客户端的 connect() 调用
    for (j = 0; j < server.ipfd_count; j++) {
     
        if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
            acceptTcpHandler,NULL) == AE_ERR)
            {
     
                redisPanic(
                    "Unrecoverable error creating server.ipfd file event.");
            }
    }
}

简要说明下。

  1. 设置Reactor
  2. 完成socket, bink, listen
  3. 注册acceptTcpHandler,相当于为反应堆注入初始事件。那么一旦连接,反应堆就会开始运作。可以猜到,在注册acceptTcpHandler中,肯定有关于1. 新连接到来的处理。
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
     
    while(max--) {
     
        // accept 客户端连接
        cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
        if (cfd == ANET_ERR) {
     
            if (errno != EWOULDBLOCK)
                redisLog(REDIS_WARNING,
                    "Accepting client connection: %s", server.neterr);
            return;
        }
        redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
        // 为客户端创建客户端状态(redisClient)
        acceptCommonHandler(cfd,0);
    }
}

当新连接到来的时候,acceptCommonHandler处理新连接

static void acceptCommonHandler(int fd, int flags) {
     
    // 为每个新连接创建客户端
    redisClient *c;
    if ((c = createClient(fd)) == NULL) {
     
        redisLog(REDIS_WARNING,
            "Error registering fd event for the new client: %s (fd=%d)",
            strerror(errno),fd);
        close(fd); /* May be already closed, just ignore errors */
        return;
    }
}
redisClient *createClient(int fd) {
     
    if (aeCreateFileEvent(server.el,fd,AE_READABLE,
            readQueryFromClient, c) == AE_ERR)
    {
     
        ...
    }
}

可以看到,为新来的连接注册了readQueryFromClient,用来处理客户端发来的命令。
剩下来的就是解析协议,然后处理命令。然后得到命令的结果。根据对应的命令去回调不同的处理函数。

void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
     
    processInputBuffer(c);
}

实际上就是在命令表中的一张大表去查找命令。

1.1 小结

明白了上面的流程处理,那么就很容易明白Redis的处理流程。那么Redis的网络编程部分就基本到此结束了。可以查看我的从零开始写一个Redis,谈到如何使用C++来写一个自己的Redis网络部分。

你可能感兴趣的:(redis源码学习)