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.");
                }
        }
    }
    

    簡単に説明します.
  • Reactor
  • の設定
  • socket,bink,listen
  • を完了
  • は、原子炉注入の初期イベントに相当するaccepttTcpHandlerを登録する.接続すると原子炉が作動しますaccepttTcpHandlerの登録には、必ず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ネットワークの部分を書くかについて話します.