设为首页 加入收藏

TOP

Redis源码整体运行流程详解(二)
2014-11-24 00:37:24 来源: 作者: 【 】 浏览:13
Tags:Redis 源码 整体 运行 流程 详解
件监听中,进行监听,由aeCreateFileEvent函数完成,其注册的listen端口可读事件处理函数为acceptTcpHandler,这样在listen端口有新连接的时候会调用acceptTcpHandler,后者在accept这个新连接,然后就可以处理后续跟这个客户端连接相关的事件了。
/* Create an event handler for accepting new connections in TCP and Unix
     * domain sockets. */
     //文件事件,用于处理响应外界的操作请求,事件处理函数为acceptTcpHandler/acceptUnixHandler
     //在networking.c
    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.");
            }
    }
    if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
        acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");

acceptTcpHandler函数

上面介绍了,initServer完成listen端口后,会加入到事件循环中,该事件为可读事件,并记录处理函数为fe->rfileProc = acceptTcpHandler;该函数分两步操作:用acceptTcpHandler接受这个客户端连接;然第二部初始化这个客户端连接的相关数据,将clientfd加入事件里面,设置的可读事件处理函数为readQueryFromClient,也就是读取客户端请求的函数。

void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    int cport, cfd;
    char cip[REDIS_IP_STR_LEN];
    REDIS_NOTUSED(el);//无意义
    REDIS_NOTUSED(mask);
    REDIS_NOTUSED(privdata);

    //cfd为accept函数返回的客户端文件描述符,accept使服务器完成一个客户端的链接
    cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
    if (cfd == AE_ERR) {
        redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr);
        return;
    }
    redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
	//将cfd加入事件循环并设置回调函数为readQueryFromClient,并初始化redisClient
    acceptCommonHandler(cfd,0);
}

第一步很简单即完成accept,主要关注第二步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;
    }
    /* If maxclient directive is set and this is one client more... close the
     * connection. Note that we create the client instead to check before
     * for this condition, since now the socket is already set in non-blocking
     * mode and we can send an error for free using the Kernel I/O */
    //当前连接的客户端数目大于服务器最大运行的连接数,则拒绝连接
    if (listLength(server.clients) > server.maxclients) {
        char *err = "-ERR max number of clients reached\r\n";

        /* That's a best effort error message, don't check write errors */
        if (write(c->fd,err,strlen(err)) == -1) {
            /* Nothing to do, Just to avoid the warning... */
        }
        server.stat_rejected_conn++;
        freeClient(c);
        return;
    }
    server.stat_numconnections++;
    c->flags |= flags;
}

createClient函数

此函数用来为新连接的客户端初始化一个redisClient数据结构,该数据结构有比较多的参数,详见redis.h。该函数完成两个操作,第一、为客户端创建事件处理函数readQueryFromClient专门接收客户端发来的指令,第二、初始化redisClient数据结构相关参数。
redisClient *createClient(int fd) {
    redisClient *c = zmalloc(sizeof(redisClient));

    /* passing -1 as fd it is possible to create a non connected client.
     * This is useful since all the Redis commands needs to be executed
     * in the context of a client. When commands are executed in other
     * contexts (for instance a Lua script) we need a non connected client. */
     /**
        因为 Redis 命令总在客户端的上下文中执行,
        有时候为了在服务器内部执行命令,需要使用伪客户端来执行命令
        在 fd == -1 时,创建的客户端为伪终端
     */
    if (fd != -1) {
        //下面三个都是设置socket属性
        anetNonBlock(NULL,fd);//非阻塞
        anetEnableTcpNoDelay(NULL,fd);//no delay
        if (server.tcpkeepalive)
            anetKeepAlive(NULL,fd,server.tcpkeepalive);//keep alive

        //创建一个accept fd的FileEvent事件,事件的处理函数是readQueryFromClient
        if (aeCreateFileEvent(server.
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 2/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇 面试-数据库性能(索引) 下一篇存储方式与介质对性能的影响

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: