Redis source code analysis (a) server and client interaction process

Redis the C / S model
Redis based on the underlying network, or request, for the stand-alone database, interactive network requests on only one machine, i.e., in a client server computer

When the input terminal redis-serve, it starts a Redis server, and then begins to initialize internal data, including for purposes of Redis

Reads the configuration file initializes the internal parameters
to create a default database (default 16)
to create listening socket bound to the callback function (connection request receiving client)
Event-driven cycle, starts responding to client requests
...
when the input terminal redis- cli when a client starts all over

Here can simply guess, Redis commands roughly interaction process

Starting a client, requests to connect to the server
the server receives the client request, establishing the connection is successful, the server and begin listening client file descriptor callback bindings
client input command causes the server side listening file becomes readable, server starts a read command
server parses the command and invoke the corresponding command handler
server processing result back to the client
a client file descriptor becomes readable, read the feedback information, the output terminal in
the above is a common C / S model, Redis Reactor using connection-mode processing, Reactor pattern is often said that a method using multiplex function io listening client. But Redis is Reactor under the single-threaded, you can use the thread pool Reactor + common method in highly concurrent server model designed to improve concurrency (also known as one loop per thread, design models muduo network library used)

Here experience from the perspective of the source server and client interaction processes (only interception of the critical section)

Server and client interaction process
server listens for client connections
when the server starts, the first execution of a server.c / main function, as described above, main function to initialize a lot of work, there is one of them is to create a listening socket

//server.c
int main (int argc, char * the argv) {
...
/
initialize the server, listening socket created * /
initServer ();
...
}
. 1
2
. 3
. 4
. 5
. 6
. 7
initServer function in the same manner as a large initialization which part is to create a listening socket

//server.c
/ * call server startup, the server initialization /
void initServer (void) {
...
/
create listening socket /
/
ipfd_count is the number of the listening socket * /
for (J = 0; J <Server. ipfd_count; J ++) {
IF (aeCreateFileEvent (server.el, server.ipfd [J], AE_READABLE,
acceptTcpHandler, NULL) == AE_ERR)
{
serverPanic (
"Unrecoverable error server.ipfd Creating File Event.");
}
}
...
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
Create listening socket function implemented by the function aeCreateFileEvent

//ae.c
/*

  • Create a file event (event-driven)

  • eventLoop: cycle event server drive array

  • fd: file descriptor

  • mask: the need to monitor events

  • proc: callback function

  • clientData: the parameters passed to the callback function
    * /
    int aeCreateFileEvent (aeEventLoop * eventLoop, FD int, int mask,
    aeFileProc proc *, void the clientData)
    {
    /
    If the file descriptor to create a predetermined size larger than the server, the error * /
    IF (FD> = eventLoop-> setSize) {
    errno = ERANGE is;
    return AE_ERR;
    }

    / * Returns the server in the event of drive cycle fd event * /
    aeFileEvent * = Fe & eventLoop-> Events [fd];

    / * File descriptor and adds it needs to listen for events multiplexing function io /
    IF (aeApiAddEvent (eventLoop, FD, mask) == -1)
    return AE_ERR;
    /
    will be saved in the event listener drive /
    Fe-> mask | = mask;
    /
    set callback /
    IF (mask & AE_READABLE) Fe-> rfileProc = proc;
    IF (mask & AE_WRITABLE) Fe-> wfileProc = proc;
    /
    setting parameters * /
    Fe-> = the clientData the clientData ;
    IF (FD> eventLoop-> maxFd)
    eventLoop-> maxFd = FD;
    return AE_OK;
    }
    . 1
    2
    . 3
    . 4
    . 5
    . 6
    . 7
    . 8
    . 9
    10
    . 11
    12 is
    13 is
    14
    15
    16
    . 17
    18 is
    . 19
    20 is
    21 is
    22 is
    23 is
    24
    25
    26 is
    27
    28
    29
    30
    31 is
    32
    33 is
    34 is
    35
    in the function aeEventLoop event-driven cycle and storage of all the events is listening, when multiplexing io returned to activate all the events will be stored in order to process aeEventLoop, and event-driven loop libevent same effect

aeFileEvent is a package of events, internal preservation listening file, the same monitor events and a callback function, and libevent events (event) action

The client receives a connection request
addition to the callback function passed aeCreateFileEvent, you can guess it's main function is to call the accept function receives client connection requests to establish file descriptor associated with the client, registered to io multiplexing. It is defined as follows

//networking.c
/ * callback server listening socket, for receiving a client connection request * /
void acceptTcpHandler (aeEventLoop EL *, int FD, privdata void *, int mask) {
int CPort, CFD, max = MAX_ACCEPTS_PER_CALL;
char CIP [NET_IP_STR_LEN];

while(max--) {
    /* 调用accept接收客户端连接请求,返回与客户端关联的文件描述符 */
    cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
    ...
    /* 根据文件描述符创建客户端实例(client对象),用于与客户端交互 */
    acceptCommonHandler(cfd,0,cip);
}

}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
every time it receives a client request, the server creates an instance of the client (client type) According to the client file descriptor, client server and the client All interactive command bridge, client input buffer is read into the client in further processing

Creating client instance
to create client instance function is defined as follows

//networking.c
/*

  • Creating client instance based on the client file descriptor
  • fd: receiving a client connection request is returned file descriptor
  • ip: Client Address <IP, Port>
    * /
    static void acceptCommonHandler (int FD, the flags int, char * IP) {
    Client C;
    /
    a client instance of the file descriptor to create a client /
    IF ((C = createClient (FD )) == NULL) {
    ServerLog (LL_WARNING,
    "Error for registering! FD The new new Client Event:% S (% FD = D)",
    the strerror (errno), FD);
    Close (FD); /
    On May BE already Closed, * the ignore errors Just /
    return;
    }
    ...
    }
    . 1
    2
    . 3
    . 4
    . 5
    . 6
    . 7
    . 8
    . 9
    10
    . 11
    12 is
    13 is
    14
    15
    16
    . 17
    18 is
    The function call createClient, execution actually create the client instance operation

//networking.c
/ * file descriptor to create a connection with the client * / The
client createClient (int FD) {
/
application client memory size * /
client C = zmalloc (the sizeof (client));
IF (FD =! -1) {
/
arranged nonblocking IO /
anetNonBlock (NULL, FD);
anetEnableTcpNoDelay (NULL, FD);
/
Keep-Alive option /
IF (server.tcpkeepalive)
anetKeepAlive (NULL, FD, server.tcpkeepalive);
/
is the connection to create an event listener readable event, the callback function * readQueryFromClient /
IF (aeCreateFileEvent (server.el, fd, AE_READABLE,
readQueryFromClient, c) == AE_ERR)
{
use Close (fd);
zfree ©;
return NULL;
}
}
...
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
created with a file descriptor associated with the event and the same as above, but where the callback becomes readQueryFromClient, since the connection is not to a connection request receiving client, but the client is configured to receive input commands.

Processing the command inputted by the client
when the client inputs a command, executes the corresponding callback function readQueryFromClient, the main function calls read function reads the input from the client file descriptor commands

//networking.c
/ * callback function when the client-readable * /
void readQueryFromClient (aeEventLoop EL *, int FD, privdata void *, int mask) {
Client C = (Client ) privdata;
int Nread, readlen;

readlen = PROTO_IOBUF_LEN;
/* 为缓冲区申请空间,用于保存客户端命令 */
c->querybuf = sdsMakeRoomFor(c->querybuf, readlen);
/* 从客户端读取命令,保存在c->querybuf中 */
nread = read(fd, c->querybuf+qblen, readlen);
...
/* 处理客户端命令 */
processInputBuffer(c);

. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
processInputBuffer option based on the client function executing different operations, functions processCommand final call processing commands, the client function to parse the command keyword, the keyword is determined whether or not legal. If legitimate, then the number of parameters to determine the legality

//server.c
/ * parse client command, first determine the legality of command keyword, and then determine the number of parameters is legal * /
int processCommand (Client c) {
...
/
Find command is the command name from the dictionary, to determine whether there the command /
/
save commands in cmd, including command processing corresponding to the function * /
the C-> the C-cmd => lastcmd = lookupCommand (the C-> the argv [0] -> PTR);
...
IF (...)
{
...
}
the else
{
// calls the command handler
call (C, CMD_CALL_FULL);
...
}
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
You can see the main function is to parse command keywords to find whether there is a dictionary from the bottom keyword, if any, will together with the corresponding handler command with cmd variable assignment to return in, cmd variable is the struct redisCommand * type, slightly after you can see the usefulness

Call function defined as follows

//server.c
/ command handler calls * * /
void Call (Client C, int the flags) {
...
/
call-up command callback * /
the C-> CMD-> proc ©;
...
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
the command structure
inside each Redis has good command and its corresponding handler packaging, this structure is struct redisCommand, two of the more important members of the variables

//server.h
struct redisCommand {
char * name; // command keyword
redisCommandProc * proc; // handler
...
};
. 1
2
. 3
. 4
. 5
. 6
when guessed here, function call lookupCommand processCommand function, will is there a command structure to find the appropriate keywords, if any, return to the cmd variable. We can now look inside each package if Redis is a command of the

redisCommand redisCommandTable struct [] = {
{ "GET", the getCommand, 2, "of rF", 0, NULL, 1,1,1,0,0},
{ "SET", the setCommand, -3, "WM", 0 , NULL, 1,1,1,0,0},
{ "SETNX", setnxCommand,. 3, "WMF", 0, NULL, 1,1,1,0,0},
{ "SETEX", setexCommand,. 4 , "WM", 0, NULL, 1,1,1,0,0},
{ "psetex", psetexCommand,. 4, "WM", 0, NULL, 1,1,1,0,0},
...
} ;
1
2
3
4
5
6
7
8
original Redis has been designed for each command structure struct redisCommand good, but to find out if there is not a direct command keywords to find one by one from the "super" in the array, as too slow. Redis is inside each command and its corresponding keyword struct redisCommand structure recorded in a dictionary, the dictionary since (implemented by the underlying hash table) lookup efficiency is O (1), so it will not cause performance bottlenecks

After obtaining the appropriate command structure, also acquired command handler, is to get order in terms of getCommand, for the purposes of the set command is setCommand, probably after the command keyword, plus Command is the corresponding command handler

So the above c-> cmd-> proc © function call when they directly call the appropriate handler, the processing is completed, send feedback to the client, complete an interaction

Summary
interact with the server or the network client is actually based on the request, the server listens to client requests, the client requests a connection, the connection is established when the server starts listening to the client's file descriptor (socket), once the client enter the command , the server will read the file descriptor obtained input client then parses, performs processing functions, the structure back to the client, the client will be displayed on the terminal configuration, complete an interaction
------------ ----
Disclaimer: this article is CSDN blogger "program slag slag a small backyard" of the original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
Original link: https: //blog.csdn.net/sinat_35261315/article/details/78966882

Published 100 original articles · won praise 12 · views 10000 +

Guess you like

Origin blog.csdn.net/hmh13548571896/article/details/103636913