Gdb debug redis-cli command sending and receiving process

With set name molaifeng, for example, in the form of debugging with gdb to discuss its implementation process within redis-cli in the client.

Note, the Redis version in this article is 6.2.4

Hit a breakpoint at cliSendCommand, and then follow the code flow.

# gdb ./src/redis-cli 
GNU gdb (GDB) 7.6.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/local/redis-6.2.4/src/redis-cli...done.
(gdb) b cliSendCommand
Breakpoint 1 at 0x413f65: file redis-cli.c, line 1320.
(gdb) r
Starting program: /usr/local/redis-6.2.4/./src/redis-cli 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
127.0.0.1:6379> 

Enter set name molaifeng in the command line and press Enter to enter the formal debugging process.

127.0.0.1:6379> set name molaifeng

Breakpoint 1, cliSendCommand (argc=3, argv=0xd08220, repeat=1) at redis-cli.c:1320
1320	    char *command = argv[0];

In order to facilitate the debugging of the code, you can enter focus to call up the code window for debugging.

   lqqredis-cli.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk                                                                                                                                                                                   x
   x1319    static int cliSendCommand(int argc, char **argv, long repeat) {                                                                                                                   x
B+>x1320        char *command = argv[0];                                                                                                                                                      x
   x1321        size_t *argvlen;                                                                                                                                                              x
   x1322        int j, output_raw;                                                                                                                                                            x
   x1323                                                                                                                                                                                      x
   x1324        if (!config.eval_ldb && /* In debugging mode, let's pass "help" to Redis. */                                                                                                  x
   x1325            (!strcasecmp(command,"help") || !strcasecmp(command,"?"))) {                                                                                                              x
   x1326            cliOutputHelp(--argc, ++argv);                                                                                                                                            x
   x1327            return REDIS_OK;                                                                                                                                                          x
   x1328        }                                                                                                                                                                             x
   x1329                                                                                                                                                                                      x
   x1330        if (context == NULL) return REDIS_ERR;                                                                                                                                        x
   x1331                                                                                                                                                                                      x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: cliSendCommand                                                                                                                           Line: 1320 PC: 0x413f65 
warning: Incorrect Number of Arguments.
Usage: focus {<win> | next | prev}


(gdb) 

You can see that the code is currently executed to line 1320, you can see the corresponding B+> on the left.

B+>x1320        char *command = argv[0];

Use p (print) to output argc and argv.

(gdb) p	argc
$1 = 3
(gdb) p	[email protected]
$2 = {0xd08220,	0x300000000, 0x5c4046e92dd9f}
(gdb) p	*[email protected]
$3 = {0xd08303 "set", 0xd08373 "name", 0xd08293 "molaifeng"}

It turned out to correspond to the command just entered.

Next, press n (next) to continue executing the code until line 1393.

   x1390        /* Negative repeat is allowed and causes infinite loop,                                                                                                                       x
   x1391           works well with the interval option. */                                                                                                                                    x
   x1392        while(repeat < 0 || repeat-- > 0) {                                                                                                                                           x
  >x1393            redisAppendCommandArgv(context,argc,(const char**)argv,argvlen);

Press s (step) to enter the redisAppendCommandArgv function.

   lqqhiredis.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x1114                                                                                                                                                                                      x
   x1115    int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {                                                                                 x
   x1116        hisds cmd;                                                                                                                                                                    x
   x1117        int len;                                                                                                                                                                      x
   x1118                                                                                                                                                                                      x
  >x1119        len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);                                                                                                                      x
   x1120        if (len == -1) {                                                                                                                                                              x
   x1121            __redisSetError(c,REDIS_ERR_OOM,"Out of memory");                                                                                                                         x
   x1122            return REDIS_ERR;                                                                                                                                                         x
   x1123        }                                                                                                                                                                             x
   x1124                                                                                                                                                                                      x
   x1125        if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {                                                                                                                            x
   x1126            hi_sdsfree(cmd);                                                                                                                                                          x
   x1127            return REDIS_ERR;                                                                                                                                                         x
   x1128        }                                                                                                                                                                             x
   x1129                                                                                                                                                                                      x
   x1130        hi_sdsfree(cmd);                                                                                                                                                              x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: redisAppendCommandArgv                                                                                                                   Line: 1119 PC: 0x42f47d 
Usage: focus {<win> | next | prev}

(gdb) s
redisAppendCommandArgv (c=0xcae070, argc=3, argv=0xd08220, argvlen=0x7ffff6c28000) at hiredis.c:1119
(gdb) 

Press s (step) to enter the redisFormatSdsCommandArgv function, and then press n (next) to execute to line 612.

			   /* Use an SDS string for command construction */                                                                                                                              
 x588         cmd = hi_sdsempty(); 
 ……
   x601         /* Construct command */                                                                                                                                                       x
   x602         cmd = hi_sdscatfmt(cmd, "*%i\r\n", argc);                                                                                                                                     x
   x603         for (j=0; j < argc; j++) {                                                                                                                                                    x
   x604             len = argvlen ? argvlen[j] : strlen(argv[j]);                                                                                                                             x
   x605             cmd = hi_sdscatfmt(cmd, "$%u\r\n", len);                                                                                                                                  x
   x606             cmd = hi_sdscatlen(cmd, argv[j], len);                                                                                                                                    x
   x607             cmd = hi_sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);                                                                                                                        x
   x608         }                                                                                                                                                                             x
   x609                                                                                                                                                                                       x
   x610         assert(hi_sdslen(cmd)==totlen);                                                                                                                                               x
   x611                                                                                                                                                                                       x
  >x612         *target = cmd;                                                                                                                                                                x
   x613         return totlen;                                                                                                                                                                x
   x614     }

Press n to execute this line of code, and then print what cmd is.

(gdb) p	cmd
$7 = (hisds) 0xcbe1f3 "*3\r\n$3\r\nset\r\n$4\r\nname\r\n$9\r\nmolaifeng\r\n"

Here is a brief introduction to the RESP protocol, the smallest unit type transmitted in RESP is as follows

  • Single-line string: start with + sign;
  • Multi-line strings start with the $ sign, followed by the length of the string;
  • Integer value starts with: symbol, followed by a string form of integer;
  • The error message starts with-symbol;
  • The array starts with *, followed by the length of the array.

Note: A carriage return and line feed symbol is added at the end of each unit\r\n

Then the cmd output can be interpreted as:

  • *3 Converted into an array with three elements inside;
  • $3\r\nset\r\n, the first element is a string with a length of 3 and a value of set;
  • $4\r\nname\r\n, the second element is a string with a length of 4 and a value of name;
  • $9\r\nmolaifeng\r\n, the last element is a string with a length of 9 and a value of molaifeng.

Press n to continue execution and return to the redisAppendCommandArgv function until line 1125.

   lqqhiredis.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x1114                                                                                                                                                                                      x
   x1115    int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) {                                                                                 x
   x1116        hisds cmd;                                                                                                                                                                    x
   x1117        int len;                                                                                                                                                                      x
   x1118                                                                                                                                                                                      x
   x1119        len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);                                                                                                                      x
   x1120        if (len == -1) {                                                                                                                                                              x
   x1121            __redisSetError(c,REDIS_ERR_OOM,"Out of memory");                                                                                                                         x
   x1122            return REDIS_ERR;                                                                                                                                                         x
   x1123        }                                                                                                                                                                             x
   x1124                                                                                                                                                                                      x
  >x1125        if (__redisAppendCommand(c,cmd,len) != REDIS_OK) {                                                                                                                            x
   x1126            hi_sdsfree(cmd);                                                                                                                                                          x
   x1127            return REDIS_ERR;                                                                                                                                                         x
   x1128        }                                                                                                                                                                             x
   x1129                                                                                                                                                                                      x
   x1130        hi_sdsfree(cmd);                                                                                                                                                              x
   x1131        return REDIS_OK;                                                                                                                                                              x
   x1132    }                                                                                                                                                                                 x
   x1133                                                                                                                                                                                      x
   x1134    /* Helper function for the redisCommand* family of functions.                                                                                                                     x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: redisAppendCommandArgv                                                                                                                   Line: 1120 PC: 0x42f499 
redisFormatSdsCommandArgv (target=0x7fffffffe4c0, argc=3, argv=0xd08220, argvlen=0x7ffff6c28000) at hiredis.c:603

Pause here, in line 1119, len is the length of the string just now, the value is 38, so __redisAppendCommand can be executed. This function is very important. Press s to enter this function and see what it does.

   lqqhiredis.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x1055    /* Helper function for the redisAppendCommand* family of functions.                                                                                                               x
   x1056     *                                                                                                                                                                                x
   x1057     * Write a formatted command to the output buffer. When this family                                                                                                               x
   x1058     * is used, you need to call redisGetReply yourself to retrieve                                                                                                                   x
   x1059     * the reply (or replies in pub/sub).                                                                                                                                             x
   x1060     */                                                                                                                                                                               x
   x1061    int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {                                                                                                          x
   x1062        hisds newbuf;                                                                                                                                                                 x
   x1063                                                                                                                                                                                      x
  >x1064        newbuf = hi_sdscatlen(c->obuf,cmd,len);                                                                                                                                       x
   x1065        if (newbuf == NULL) {                                                                                                                                                         x
   x1066            __redisSetError(c,REDIS_ERR_OOM,"Out of memory");                                                                                                                         x
   x1067            return REDIS_ERR;                                                                                                                                                         x
   x1068        }                                                                                                                                                                             x
   x1069                                                                                                                                                                                      x
   x1070        c->obuf = newbuf;                                                                                                                                                             x
   x1071        return REDIS_OK;                                                                                                                                                              x
   x1072    }                                                                                                                                                                                 x
   x1073                                                                                                                                                                                      x
   x1074    int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) {                                                                                                   x
   x1075                                                                                                                                                                                      x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: __redisAppendCommand    

By reading the code, it can be concluded that __redisAppendCommand is mainly used to write the command to be sent into the output buffer c->obuf of the context object, which can be verified by printing c->obuf.

(gdb) p	c->obuf
$13 = 0xcbe253 "*3\r\n$3\r\nset\r\n$4\r\nname\r\n$9\r\nmolaifeng\r\n"

At this time, make a breakpoint in redisGetReply, and then press c (continue) to resume the program execution to the redisGetReply breakpoint.

   lqqhiredis.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x1012    }                                                                                                                                                                                 x
   x1013                                                                                                                                                                                      x
   x1014    int redisGetReply(redisContext *c, void **reply) {                                                                                                                                x
B+>x1015        int wdone = 0;                                                                                                                                                                x
   x1016        void *aux = NULL;                                                                                                                                                             x
   x1017                                                                                                                                                                                      x
   x1018        /* Try to read pending replies */                                                                                                                                             x
   x1019        if (redisGetReplyFromReader(c,&aux) == REDIS_ERR)                                                                                                                             x
   x1020            return REDIS_ERR;                                                                                                                                                         x
   x1021                                                                                                                                                                                      x
   x1022        /* For the blocking context, flush output buffer and read reply */                                                                                                            x
   x1023        if (aux == NULL && c->flags & REDIS_BLOCK) {                                                                                                                                  x
   x1024            /* Write until done */                                                                                                                                                    x
   x1025            do {                                                                                                                                                                      x
   x1026                if (redisBufferWrite(c,&wdone) == REDIS_ERR)                                                                                                                          x
   x1027                    return REDIS_ERR;                                                                                                                                                 x
   x1028            } while (!wdone);                                                                                                                                                         x
   x1029                                                                                                                                                                                      x
   x1030            /* Read until there is a reply */                                                                                                                                         x
   x1031            do {                                                                                                                                                                      x
   x1032                if (redisBufferRead(c) == REDIS_ERR)                                                                                                                                  x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: redisGetReply                                                                                                                            Line: 1015 PC: 0x42f127 
(gdb) b redisGetReply 
Breakpoint 23 at 0x42f127: file	hiredis.c, line	1015
(gdb) c

Press n and then s to enter the redisBufferWrite function.

   lqqhiredis.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x957      * successfully written to the socket. When the buffer is empty after the                                                                                                         x
   x958      * write operation, "done" is set to 1 (if given).                                                                                                                                x
   x959      *                                                                                                                                                                                x
   x960      * Returns REDIS_ERR if an error occurred trying to write and sets                                                                                                                x
   x961      * c->errstr to hold the appropriate error string.                                                                                                                                x
   x962      */                                                                                                                                                                               x
   x963     int redisBufferWrite(redisContext *c, int *done) {                                                                                                                                x
   x964                                                                                                                                                                                       x
   x965         /* Return early when the context has seen an error. */                                                                                                                        x
  >x966         if (c->err)                                                                                                                                                                   x
   x967             return REDIS_ERR;                                                                                                                                                         x
   x968                                                                                                                                                                                       x
   x969         if (hi_sdslen(c->obuf) > 0) {                                                                                                                                                 x
   x970             ssize_t nwritten = c->funcs->write(c);                                                                                                                                    x
   x971             if (nwritten < 0) {                                                                                                                                                       x
   x972                 return REDIS_ERR;                                                                                                                                                     x
   x973             } else if (nwritten > 0) {                                                                                                                                                x
   x974                 if (nwritten == (ssize_t)hi_sdslen(c->obuf)) {                                                                                                                        x
   x975                     hi_sdsfree(c->obuf);                                                                                                                                              x
   x976                     c->obuf = hi_sdsempty();                                                                                                                                          x
   x977                     if (c->obuf == NULL)                                                                                                                                              x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: redisBufferWrite                                                                                                                         Line: 966  PC: 0x42ef2a 
warning: Incorrect Number of Arguments.

Here we focus on the next line 970 c->funcs->write(c), press s to enter this final calling function.

   x82      ssize_t redisNetWrite(redisContext *c) {                                                                                                                                          x
  >x83          ssize_t nwritten = send(c->fd, c->obuf, hi_sdslen(c->obuf), 0);                                                                                                               x
   x84          if (nwritten < 0) {                                                                                                                                                           x
   x85              if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {                                                                                            x
   x86                  /* Try again later */                                                                                                                                                 x
   x87              } else {                                                                                                                                                                  x
   x88                  __redisSetError(c, REDIS_ERR_IO, NULL);                                                                                                                               x
   x89                  return -1;                                                                                                                                                            x
   x90              }                                                                                                                                                                         x
   x91          }                                                                                                                                                                             x
   x92          return nwritten;                                                                                                                                                              x
   x93      }

It is found that the string in the c->obuf buffer is sent out through the send method, and you can check the call stack.

(gdb) bt
#0  redisNetWrite (c=0xcae070) at net.c:83
#1  0x000000000042ef6f in redisBufferWrite (c=0xcae070,	done=0x7fffffffe46c) at hiredis.c:970
#2  0x000000000042f18d in redisGetReply	(c=0xcae070, reply=0x7fffffffe498) at hiredis.c:1026
#3  0x0000000000413c92 in cliReadReply (output_raw_strings=0) at redis-cli.c:1251
#4  0x000000000041452e in cliSendCommand (argc=3, argv=0xd00b60, repeat=0) at redis-cli.c:1426
#5  0x00000000004163ca in issueCommandRepeat (argc=3, argv=0xd00b60, repeat=1) at redis-cli.c:1996
#6  0x0000000000416b8a in repl () at redis-cli.c:2192
#7  0x0000000000428ead in main (argc=0,	argv=0x7fffffffe710) at redis-cli.c:8390

The next step is to call read to read the returned result of the Redis server. Then hit a breakpoint in redisBufferRead and see what is returned.

(gdb) b	redisBufferRead	
Breakpoint 3 at	0x42ee50: file hiredis.c, line 938.

Press c to execute this function directly, and then trace line 941 nread = c->funcs->read(c, buf, sizeof(buf));

   lqqhiredis.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x932      * see if there is a reply available. */                                                                                                                                          x
   x933     int redisBufferRead(redisContext *c) {                                                                                                                                            x
   x934         char buf[1024*16];                                                                                                                                                            x
   x935         int nread;                                                                                                                                                                    x
   x936                                                                                                                                                                                       x
   x937         /* Return early when the context has seen an error. */                                                                                                                        x
   x938         if (c->err)                                                                                                                                                                   x
   x939             return REDIS_ERR;                                                                                                                                                         x
   x940                                                                                                                                                                                       x
B+>x941         nread = c->funcs->read(c, buf, sizeof(buf));                                                                                                                                  x
   x942         if (nread > 0) {                                                                                                                                                              x
   x943             if (redisReaderFeed(c->reader, buf, nread) != REDIS_OK) {                                                                                                                 x
   x944                 __redisSetError(c, c->reader->err, c->reader->errstr);                                                                                                                x
   x945                 return REDIS_ERR;                                                                                                                                                     x
   x946             } else {                                                                                                                                                                  x
   x947             }                                                                                                                                                                         x
   x948         } else if (nread < 0) {                                                                                                                                                       x
   x949             return REDIS_ERR;                                                                                                                                                         x
   x950         }                                                                                                                                                                             x
   x951         return REDIS_OK;                                                                                                                                                              x
   x952     }                                                                                                                                                                                 x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: redisBufferRead  

(gdb) n
(gdb) s                 

The recv that was finally called was found to read the return value of the Redis Server.

   lqqnet.cqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
   x60      ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {                                                                                                                 x
  >x61          ssize_t nread = recv(c->fd, buf, bufcap, 0);                                                                                                                                  x
   x62          if (nread == -1) {                                                                                                                                                            x
   x63              if ((errno == EWOULDBLOCK && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) {                                                                                            x
   x64                  /* Try again later */                                                                                                                                                 x
   x65                  return 0;                                                                                                                                                             x
   x66              } else if(errno == ETIMEDOUT && (c->flags & REDIS_BLOCK)) {                                                                                                               x
   x67                  /* especially in windows */                                                                                                                                           x
   x68                  __redisSetError(c, REDIS_ERR_TIMEOUT, "recv timeout");                                                                                                                x
   x69                  return -1;                                                                                                                                                            x
   x70              } else {                                                                                                                                                                  x
   x71                  __redisSetError(c, REDIS_ERR_IO, NULL);                                                                                                                               x
   x72                  return -1;                                                                                                                                                            x
   x73              }                                                                                                                                                                         x
   x74          } else if (nread == 0) {                                                                                                                                                      x
   x75              __redisSetError(c, REDIS_ERR_EOF, "Server closed the connection");                                                                                                        x
   x76              return -1;                                                                                                                                                                x
   x77          } else {                                                                                                                                                                      x
   x78              return nread;                                                                                                                                                             x
   x79          }                                                                                                                                                                             x
   x80      }                                                                                                                                                                                 x
   mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
multi-thre Thread 0x7ffff In: redisNetRead

Print the call stack.

#0  redisNetRead (c=0xcae070, 
    buf=0x7fffffffa420 "+OK\r\n\r\n*3\r\[email protected]\r\[email protected]\r\[email protected]\r\n*7\r\n$10\r\nzdiffstore\r\n:-4\r\n*3\r\n+write\r\n+denyoom\r\n+movablekeys\r\n:1\r\n:1\r\n:1\r\n*3\r\[email protected]\r\[email protected]
edset\r\[email protected]\r\n*7\r\n$3\r\nttl\r\n:2\r\n*3\r\n+readonly\r\n+random\r\n+fast\r\n:1\r\n:1\r\n"..., bufcap=16384) at net.c:61
#1  0x000000000042ee91 in redisBufferRead (c=0xcae070) at hiredis.c:941
#2  0x000000000042f1af in redisGetReply	(c=0xcae070, reply=0x7fffffffe498) at hiredis.c:1032
#3  0x0000000000413c92 in cliReadReply (output_raw_strings=0) at redis-cli.c:1251
#4  0x000000000041452e in cliSendCommand (argc=3, argv=0xd01b70, repeat=0) at redis-cli.c:1426
#5  0x00000000004163ca in issueCommandRepeat (argc=3, argv=0xd01b70, repeat=1) at redis-cli.c:1996
#6  0x0000000000416b8a in repl () at redis-cli.c:2192
#7  0x0000000000428ead in main (argc=0,	argv=0x7fffffffe710) at redis-cli.c:8390

At this point, the entire call flow of redis-cli is clear.

Note: Careful readers may have noticed the large string of strings output by buf. What does this have to do with only returning ok after the set command is successfully executed? The key is that recv returns the received length. For example, here is 5, then the corresponding buf is +ok\r\n at the beginning. In the above RESP, + represents a single-line string, and \r\n is a newline, which is the same as The ok output in the command line corresponds to it.

ps: In addition, if you don't want to be so troublesome, you just want to know what redis-cli sends or receives. What should we do? Here is a practical method to capture packets.

First open a Redis service on this machine,

./src/redis-server

Then grab the packet on this machine,

Note: Since 127.0.0.1 is connected in the configuration, tcpdump captures the local loopback packet
tcpdump -v tcp port 6379 -i lo -w gw.cap

Finally, open a redis-cli client on this machine, enter it set name molaifeng, then open the generated gw.cap file, you can clearly see the sent and received data.

Insert picture description here


Insert picture description here