本文共 25602 字,大约阅读时间需要 85 分钟。
这份代码是redis的client接口,其和server端的交互使用了deps目录下的hiredis c库,同时,在这部分代码中,应用了linenoise库完成类似history命令查询、自动补全等终端控制功能。
1 #include "fmacros.h" //用于mac下的兼容性处理 2 #include "version.h" //版本信息头文件,当前版本是2.4.10 3 4 #include5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 14 #include "hiredis.h" //redis 客户端库的头文件 15 #include "sds.h" 16 #include "zmalloc.h" 17 #include "linenoise.h" //终端控制库的头文件 18 #include "help.h" //当前所有的命令文件汇总,用于tab自动补全功能的源数据/* help entry的结构如下:
struct commandHelp { 20 char *name; //命令名字 21 char *params; //参数格式 22 char *summary; //简单的解释信息 23 int group; //命令类型(当前版本共分10种不同类型的命令) 24 char *since; //从哪个版本开始支持此命令 25 } */
19 20 #define REDIS_NOTUSED(V) ((void) V) 21 22 static redisContext *context; //维护client和server端的连接信息,包括文件描述符,错误信息等,参见deps/hiredis/hiredis.h 23 static struct config { 24 char *hostip; 25 int hostport; 26 char *hostsocket; 27 long repeat; //命令重复执行次数 28 long interval; //命令重复执行间隔 29 int dbnum; // db no. 30 int interactive; //交互模式 or 命令模式 31 int shutdown; 32 int monitor_mode; //监控模式 33 int pubsub_mode; //pub sub模式 34 int latency_mode; //该模式测试cli到server执行ping命令的时间间隔(应用层ping) 35 int stdinarg; /* get last arg from stdin. (-x option) */ 36 char *auth; //需要鉴权时的密码信息 37 int raw_output; /* output mode per command */ //选择该模式,将不会添加类似(interger),参见 38 sds mb_delim; 39 char prompt[128]; 40 } config; 41 42 static void usage(); 43 char *redisGitSHA1(void); 44 char *redisGitDirty(void); 45 46 /*------------------------------------------------------------------------------ 47 * Utility functions 48 *--------------------------------------------------------------------------- */ 49 50 static long long mstime(void) { 51 struct timeval tv; 52 long long mst; 53 54 gettimeofday(&tv, NULL); 55 mst = ((long)tv.tv_sec)*1000; 56 mst += tv.tv_usec/1000; 57 return mst; 58 } 59 60 static void cliRefreshPrompt(void) { 61 int len; 62 63 if (config.hostsocket != NULL) 64 len = snprintf(config.prompt,sizeof(config.prompt),"redis %s", 65 config.hostsocket); 66 else 67 len = snprintf(config.prompt,sizeof(config.prompt),"redis %s:%d", 68 config.hostip, config.hostport); 69 /* Add [dbnum] if needed */ 70 if (config.dbnum != 0) 71 len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]", 72 config.dbnum); 73 snprintf(config.prompt+len,sizeof(config.prompt)-len,"> "); 74 } 75 76 /*------------------------------------------------------------------------------ 77 * Help functions 78 *--------------------------------------------------------------------------- */ 79 80 #define CLI_HELP_COMMAND 1 81 #define CLI_HELP_GROUP 2 82 83 typedef struct { 84 int type; 85 int argc; 86 sds *argv; 87 sds full; 88 89 /* Only used for help on commands */ 90 struct commandHelp *org; 91 } helpEntry; 92 93 static helpEntry *helpEntries; 94 static int helpEntriesLen; 95 96 static sds cliVersion() { 97 sds version; 98 version = sdscatprintf(sdsempty(), "%s", REDIS_VERSION); 99 100 /* Add git commit and working tree status when available */101 if (strtoll(redisGitSHA1(),NULL,16)) {102 version = sdscatprintf(version, " (git:%s", redisGitSHA1());103 if (strtoll(redisGitDirty(),NULL,10))104 version = sdscatprintf(version, "-dirty");105 version = sdscat(version, ")");106 }107 return version;108 }109 110 static void cliInitHelp() {111 int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);112 int groupslen = sizeof(commandGroups)/sizeof(char*);113 int i, len, pos = 0;114 helpEntry tmp;115 116 helpEntriesLen = len = commandslen+groupslen;117 helpEntries = malloc(sizeof(helpEntry)*len);118 119 for (i = 0; i < groupslen; i++) {120 tmp.argc = 1;121 tmp.argv = malloc(sizeof(sds));122 tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]);123 tmp.full = tmp.argv[0];124 tmp.type = CLI_HELP_GROUP;125 tmp.org = NULL;126 helpEntries[pos++] = tmp;127 }128 129 for (i = 0; i < commandslen; i++) {130 tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc);131 tmp.full = sdsnew(commandHelp[i].name);132 tmp.type = CLI_HELP_COMMAND;133 tmp.org = &commandHelp[i];134 helpEntries[pos++] = tmp;135 }136 }137 138 /* Output command help to stdout. */139 static void cliOutputCommandHelp(struct commandHelp *help, int group) {140 printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params);141 printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary);142 printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since);143 if (group) {144 printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]);145 }146 }147 148 /* Print generic help. */149 static void cliOutputGenericHelp() {150 sds version = cliVersion();151 printf(152 "redis-cli %s\r\n"153 "Type: \"help @\" to get a list of commands in \r\n"154 " \"help \" for help on \r\n"155 " \"help \" to get a list of possible help topics\r\n"156 " \"quit\" to exit\r\n",157 version158 );159 sdsfree(version);160 }161 162 /* Output all command help, filtering by group or command name. */163 static void cliOutputHelp(int argc, char **argv) {164 int i, j, len;165 int group = -1;166 helpEntry *entry;167 struct commandHelp *help;168 169 if (argc == 0) {170 cliOutputGenericHelp();171 return;172 } else if (argc > 0 && argv[0][0] == '@') {173 len = sizeof(commandGroups)/sizeof(char*);174 for (i = 0; i < len; i++) {175 if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) {176 group = i;177 break;178 }179 }180 }181 182 assert(argc > 0);183 for (i = 0; i < helpEntriesLen; i++) {184 entry = &helpEntries[i];185 if (entry->type != CLI_HELP_COMMAND) continue;186 187 help = entry->org;188 if (group == -1) {189 /* Compare all arguments */190 if (argc == entry->argc) {191 for (j = 0; j < argc; j++) {192 if (strcasecmp(argv[j],entry->argv[j]) != 0) break;193 }194 if (j == argc) {195 cliOutputCommandHelp(help,1);196 }197 }198 } else {199 if (group == help->group) {200 cliOutputCommandHelp(help,0);201 }202 }203 }204 printf("\r\n");205 }206 207 static void completionCallback(const char *buf, linenoiseCompletions *lc) {208 size_t startpos = 0;209 int mask;210 int i;211 size_t matchlen;212 sds tmp;213 214 if (strncasecmp(buf,"help ",5) == 0) {215 startpos = 5;216 while (isspace(buf[startpos])) startpos++;217 mask = CLI_HELP_COMMAND | CLI_HELP_GROUP;218 } else {219 mask = CLI_HELP_COMMAND;220 }221 222 for (i = 0; i < helpEntriesLen; i++) {223 if (!(helpEntries[i].type & mask)) continue;224 225 matchlen = strlen(buf+startpos);226 if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) {227 tmp = sdsnewlen(buf,startpos);228 tmp = sdscat(tmp,helpEntries[i].full);229 linenoiseAddCompletion(lc,tmp);230 sdsfree(tmp);231 }232 }233 }234 235 /*------------------------------------------------------------------------------236 * Networking / parsing237 *--------------------------------------------------------------------------- */238 239 /* Send AUTH command to the server */240 static int cliAuth() {241 redisReply *reply;242 if (config.auth == NULL) return REDIS_OK;243 244 reply = redisCommand(context,"AUTH %s",config.auth);245 if (reply != NULL) {246 freeReplyObject(reply);247 return REDIS_OK;248 }249 return REDIS_ERR;250 }251 252 /* Send SELECT dbnum to the server */253 static int cliSelect() {254 redisReply *reply;255 if (config.dbnum == 0) return REDIS_OK;256 257 reply = redisCommand(context,"SELECT %d",config.dbnum);258 if (reply != NULL) {259 freeReplyObject(reply);260 return REDIS_OK;261 }262 return REDIS_ERR;263 }264 265 /* Connect to the client. If force is not zero the connection is performed266 * even if there is already a connected socket. */267 static int cliConnect(int force) {268 if (context == NULL || force) {269 if (context != NULL)270 redisFree(context);271 272 if (config.hostsocket == NULL) {273 context = redisConnect(config.hostip,config.hostport);274 } else {275 context = redisConnectUnix(config.hostsocket);276 }277 278 if (context->err) {279 fprintf(stderr,"Could not connect to Redis at ");280 if (config.hostsocket == NULL)281 fprintf(stderr,"%s:%d: %s\n",config.hostip,config.hostport,context->errstr);282 else283 fprintf(stderr,"%s: %s\n",config.hostsocket,context->errstr);284 redisFree(context);285 context = NULL;286 return REDIS_ERR;287 }288 289 /* Do AUTH and select the right DB. */290 if (cliAuth() != REDIS_OK)291 return REDIS_ERR;292 if (cliSelect() != REDIS_OK)293 return REDIS_ERR;294 }295 return REDIS_OK;296 }297 298 static void cliPrintContextError() {299 if (context == NULL) return;300 fprintf(stderr,"Error: %s\n",context->errstr);301 }302 303 static sds cliFormatReplyTTY(redisReply *r, char *prefix) {304 sds out = sdsempty();305 switch (r->type) {306 case REDIS_REPLY_ERROR:307 out = sdscatprintf(out,"(error) %s\n", r->str);308 break;309 case REDIS_REPLY_STATUS:310 out = sdscat(out,r->str);311 out = sdscat(out,"\n");312 break;313 case REDIS_REPLY_INTEGER:314 out = sdscatprintf(out,"(integer) %lld\n",r->integer);315 break;316 case REDIS_REPLY_STRING:317 /* If you are producing output for the standard output we want318 * a more interesting output with quoted characters and so forth */319 out = sdscatrepr(out,r->str,r->len);320 out = sdscat(out,"\n");321 break;322 case REDIS_REPLY_NIL:323 out = sdscat(out,"(nil)\n");324 break;325 case REDIS_REPLY_ARRAY:326 if (r->elements == 0) {327 out = sdscat(out,"(empty list or set)\n");328 } else {329 unsigned int i, idxlen = 0;330 char _prefixlen[16];331 char _prefixfmt[16];332 sds _prefix;333 sds tmp;334 335 /* Calculate chars needed to represent the largest index */336 i = r->elements;337 do {338 idxlen++;339 i /= 10;340 } while(i);341 342 /* Prefix for nested multi bulks should grow with idxlen+2 spaces */343 memset(_prefixlen,' ',idxlen+2);344 _prefixlen[idxlen+2] = '\0';345 _prefix = sdscat(sdsnew(prefix),_prefixlen);346 347 /* Setup prefix format for every entry */348 snprintf(_prefixfmt,sizeof(_prefixfmt),"%%s%%%dd) ",idxlen);349 350 for (i = 0; i < r->elements; i++) {351 /* Don't use the prefix for the first element, as the parent352 * caller already prepended the index number. */353 out = sdscatprintf(out,_prefixfmt,i == 0 ? "" : prefix,i+1);354 355 /* Format the multi bulk entry */356 tmp = cliFormatReplyTTY(r->element[i],_prefix);357 out = sdscatlen(out,tmp,sdslen(tmp));358 sdsfree(tmp);359 }360 sdsfree(_prefix);361 }362 break;363 default:364 fprintf(stderr,"Unknown reply type: %d\n", r->type);365 exit(1);366 }367 return out;368 }369 370 static sds cliFormatReplyRaw(redisReply *r) {371 sds out = sdsempty(), tmp;372 size_t i;373 374 switch (r->type) {375 case REDIS_REPLY_NIL:376 /* Nothing... */377 break;378 case REDIS_REPLY_ERROR:379 out = sdscatlen(out,r->str,r->len);380 out = sdscatlen(out,"\n",1);381 break;382 case REDIS_REPLY_STATUS:383 case REDIS_REPLY_STRING:384 out = sdscatlen(out,r->str,r->len);385 break;386 case REDIS_REPLY_INTEGER:387 out = sdscatprintf(out,"%lld",r->integer);388 break;389 case REDIS_REPLY_ARRAY:390 for (i = 0; i < r->elements; i++) {391 if (i > 0) out = sdscat(out,config.mb_delim);392 tmp = cliFormatReplyRaw(r->element[i]);393 out = sdscatlen(out,tmp,sdslen(tmp));394 sdsfree(tmp);395 }396 break;397 default:398 fprintf(stderr,"Unknown reply type: %d\n", r->type);399 exit(1);400 }401 return out;402 }403 404 static int cliReadReply(int output_raw_strings) {405 void *_reply;406 redisReply *reply;407 sds out;408 409 if (redisGetReply(context,&_reply) != REDIS_OK) {410 if (config.shutdown)411 return REDIS_OK;412 if (config.interactive) {413 /* Filter cases where we should reconnect */414 if (context->err == REDIS_ERR_IO && errno == ECONNRESET)415 return REDIS_ERR;416 if (context->err == REDIS_ERR_EOF)417 return REDIS_ERR;418 }419 cliPrintContextError();420 exit(1);421 return REDIS_ERR; /* avoid compiler warning */422 }423 424 reply = (redisReply*)_reply;425 if (output_raw_strings) {426 out = cliFormatReplyRaw(reply);427 } else {428 if (config.raw_output) {429 out = cliFormatReplyRaw(reply);430 out = sdscat(out,"\n");431 } else {432 out = cliFormatReplyTTY(reply,"");433 }434 }435 fwrite(out,sdslen(out),1,stdout);436 sdsfree(out);437 freeReplyObject(reply);438 return REDIS_OK;439 }440 441 static int cliSendCommand(int argc, char **argv, int repeat) {442 char *command = argv[0];443 size_t *argvlen;444 int j, output_raw;445 446 if (!strcasecmp(command,"help") || !strcasecmp(command,"?")) {447 cliOutputHelp(--argc, ++argv);448 return REDIS_OK;449 }450 451 if (context == NULL) return REDIS_ERR;452 453 output_raw = 0;454 if (!strcasecmp(command,"info") ||455 (argc == 2 && !strcasecmp(command,"client") &&456 !strcasecmp(argv[1],"list")))457 458 {459 output_raw = 1;460 }461 462 if (!strcasecmp(command,"shutdown")) config.shutdown = 1;463 if (!strcasecmp(command,"monitor")) config.monitor_mode = 1;464 if (!strcasecmp(command,"subscribe") ||465 !strcasecmp(command,"psubscribe")) config.pubsub_mode = 1;466 467 /* Setup argument length */468 argvlen = malloc(argc*sizeof(size_t));469 for (j = 0; j < argc; j++)470 argvlen[j] = sdslen(argv[j]);471 472 while(repeat--) {473 redisAppendCommandArgv(context,argc,(const char**)argv,argvlen);474 while (config.monitor_mode) {475 if (cliReadReply(output_raw) != REDIS_OK) exit(1);476 fflush(stdout);477 }478 479 if (config.pubsub_mode) {480 if (!config.raw_output)481 printf("Reading messages... (press Ctrl-C to quit)\n");482 while (1) {483 if (cliReadReply(output_raw) != REDIS_OK) exit(1);484 }485 }486 487 if (cliReadReply(output_raw) != REDIS_OK) {488 free(argvlen);489 return REDIS_ERR;490 } else {491 /* Store database number when SELECT was successfully executed. */492 if (!strcasecmp(command,"select") && argc == 2) {493 config.dbnum = atoi(argv[1]);494 cliRefreshPrompt();495 }496 }497 if (config.interval) usleep(config.interval);498 fflush(stdout); /* Make it grep friendly */499 }500 501 free(argvlen);502 return REDIS_OK;503 }504 505 /*------------------------------------------------------------------------------506 * User interface507 *--------------------------------------------------------------------------- */508 509 static int parseOptions(int argc, char **argv) {510 int i;511 512 for (i = 1; i < argc; i++) {513 int lastarg = i==argc-1;514 515 if (!strcmp(argv[i],"-h") && !lastarg) {516 sdsfree(config.hostip);517 config.hostip = sdsnew(argv[i+1]);518 i++;519 } else if (!strcmp(argv[i],"-h") && lastarg) {520 usage();521 } else if (!strcmp(argv[i],"--help")) {522 usage();523 } else if (!strcmp(argv[i],"-x")) {524 config.stdinarg = 1;525 } else if (!strcmp(argv[i],"-p") && !lastarg) {526 config.hostport = atoi(argv[i+1]);527 i++;528 } else if (!strcmp(argv[i],"-s") && !lastarg) {529 config.hostsocket = argv[i+1];530 i++;531 } else if (!strcmp(argv[i],"-r") && !lastarg) {532 config.repeat = strtoll(argv[i+1],NULL,10);533 i++;534 } else if (!strcmp(argv[i],"-i") && !lastarg) {535 double seconds = atof(argv[i+1]);536 config.interval = seconds*1000000;537 i++;538 } else if (!strcmp(argv[i],"-n") && !lastarg) {539 config.dbnum = atoi(argv[i+1]);540 i++;541 } else if (!strcmp(argv[i],"-a") && !lastarg) {542 config.auth = argv[i+1];543 i++;544 } else if (!strcmp(argv[i],"--raw")) {545 config.raw_output = 1;546 } else if (!strcmp(argv[i],"--latency")) {547 config.latency_mode = 1;548 } else if (!strcmp(argv[i],"-d") && !lastarg) {549 sdsfree(config.mb_delim);550 config.mb_delim = sdsnew(argv[i+1]);551 i++;552 } else if (!strcmp(argv[i],"-v") || !strcmp(argv[i], "--version")) {553 sds version = cliVersion();554 printf("redis-cli %s\n", version);555 sdsfree(version);556 exit(0);557 } else {558 break;559 }560 }561 return i;562 }563 564 static sds readArgFromStdin(void) {565 char buf[1024];566 sds arg = sdsempty();567 568 while(1) {569 int nread = read(fileno(stdin),buf,1024);570 571 if (nread == 0) break;572 else if (nread == -1) {573 perror("Reading from standard input");574 exit(1);575 }576 arg = sdscatlen(arg,buf,nread);577 }578 return arg;579 }580 581 static void usage() {582 sds version = cliVersion();583 fprintf(stderr,584 "redis-cli %s\n"585 "\n"586 "Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]\n"587 " -h Server hostname (default: 127.0.0.1)\n"588 " -p Server port (default: 6379)\n"589 " -s Server socket (overrides hostname and port)\n"590 " -a Password to use when connecting to the server\n"591 " -r Execute specified command N times\n"592 " -i When -r is used, waits seconds per command.\n"593 " It is possible to specify sub-second times like -i 0.1.\n"594 " -n Database number\n"595 " -x Read last argument from STDIN\n"596 " -d Multi-bulk delimiter in for raw formatting (default: \\n)\n"597 " --raw Use raw formatting for replies (default when STDOUT is not a tty)\n"598 " --latency Enter a special mode continuously sampling latency.\n"599 " --help Output this help and exit\n"600 " --version Output version and exit\n"601 "\n"602 "Examples:\n"603 " cat /etc/passwd | redis-cli -x set mypasswd\n"604 " redis-cli get mypasswd\n"605 " redis-cli -r 100 lpush mylist x\n"606 " redis-cli -r 100 -i 1 info | grep used_memory_human:\n"607 "\n"608 "When no command is given, redis-cli starts in interactive mode.\n"609 "Type \"help\" in interactive mode for information on available commands.\n"610 "\n",611 version);612 sdsfree(version);613 exit(1);614 }615 616 /* Turn the plain C strings into Sds strings */617 static char **convertToSds(int count, char** args) {618 int j;619 char **sds = zmalloc(sizeof(char*)*count);620 621 for(j = 0; j < count; j++)622 sds[j] = sdsnew(args[j]);623 624 return sds;625 }626 627 #define LINE_BUFLEN 4096628 static void repl() {629 sds historyfile = NULL;630 int history = 0;631 char *line;632 int argc;633 sds *argv;634 635 config.interactive = 1;636 linenoiseSetCompletionCallback(completionCallback);637 638 /* Only use history when stdin is a tty. */639 if (isatty(fileno(stdin))) {640 history = 1;641 642 if (getenv("HOME") != NULL) {643 historyfile = sdscatprintf(sdsempty(),"%s/.rediscli_history",getenv("HOME"));644 linenoiseHistoryLoad(historyfile);645 }646 }647 648 cliRefreshPrompt();649 while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {650 if (line[0] != '\0') {651 argv = sdssplitargs(line,&argc);652 if (history) linenoiseHistoryAdd(line);653 if (historyfile) linenoiseHistorySave(historyfile);654 655 if (argv == NULL) {656 printf("Invalid argument(s)\n");657 free(line);658 continue;659 } else if (argc > 0) {660 if (strcasecmp(argv[0],"quit") == 0 ||661 strcasecmp(argv[0],"exit") == 0)662 {663 exit(0);664 } else if (argc == 3 && !strcasecmp(argv[0],"connect")) {665 sdsfree(config.hostip);666 config.hostip = sdsnew(argv[1]);667 config.hostport = atoi(argv[2]);668 cliConnect(1);669 } else if (argc == 1 && !strcasecmp(argv[0],"clear")) {670 linenoiseClearScreen();671 } else {672 long long start_time = mstime(), elapsed;673 int repeat, skipargs = 0;674 675 repeat = atoi(argv[0]);676 if (argc > 1 && repeat) {677 skipargs = 1;678 } else {679 repeat = 1;680 }681 682 if (cliSendCommand(argc-skipargs,argv+skipargs,repeat)683 != REDIS_OK)684 {685 cliConnect(1);686 687 /* If we still cannot send the command print error.688 * We'll try to reconnect the next time. */689 if (cliSendCommand(argc-skipargs,argv+skipargs,repeat)690 != REDIS_OK)691 cliPrintContextError();692 }693 elapsed = mstime()-start_time;694 if (elapsed >= 500) {695 printf("(%.2fs)\n",(double)elapsed/1000);696 }697 }698 }699 /* Free the argument vector */700 while(argc--) sdsfree(argv[argc]);701 zfree(argv);702 }703 /* linenoise() returns malloc-ed lines like readline() */704 free(line);705 }706 exit(0);707 }708 709 static int noninteractive(int argc, char **argv) {710 int retval = 0;711 if (config.stdinarg) {712 argv = zrealloc(argv, (argc+1)*sizeof(char*));713 argv[argc] = readArgFromStdin();714 retval = cliSendCommand(argc+1, argv, config.repeat);715 } else {716 /* stdin is probably a tty, can be tested with S_ISCHR(s.st_mode) */717 retval = cliSendCommand(argc, argv, config.repeat);718 }719 return retval;720 }721 722 static void latencyMode(void) {723 redisReply *reply;724 long long start, latency, min, max, tot, count = 0;725 double avg;726 727 if (!context) exit(1);728 while(1) {729 start = mstime();730 reply = redisCommand(context,"PING");731 if (reply == NULL) {732 fprintf(stderr,"\nI/O error\n");733 exit(1);734 }735 latency = mstime()-start;736 freeReplyObject(reply);737 count++;738 if (count == 1) {739 min = max = tot = latency;740 avg = (double) latency;741 } else {742 if (latency < min) min = latency;743 if (latency > max) max = latency;744 tot += latency;745 avg = (double) tot/count;746 }747 printf("\x1b[0G\x1b[2Kmin: %lld, max: %lld, avg: %.2f (%lld samples)",748 min, max, avg, count);749 fflush(stdout);750 usleep(10000);751 }752 }753 754 int main(int argc, char **argv) {755 int firstarg;756 757 config.hostip = sdsnew("127.0.0.1");758 config.hostport = 6379;759 config.hostsocket = NULL;760 config.repeat = 1;761 config.interval = 0;762 config.dbnum = 0;763 config.interactive = 0;764 config.shutdown = 0;765 config.monitor_mode = 0;766 config.pubsub_mode = 0;767 config.latency_mode = 0;768 config.stdinarg = 0;769 config.auth = NULL;770 config.raw_output = !isatty(fileno(stdout)) && (getenv("FAKETTY") == NULL);771 config.mb_delim = sdsnew("\n");772 cliInitHelp();773 774 firstarg = parseOptions(argc,argv);775 argc -= firstarg;776 argv += firstarg;777 778 /* Start in latency mode if appropriate */779 if (config.latency_mode) {780 cliConnect(0);781 latencyMode();782 }783 784 /* Start interactive mode when no command is provided */785 if (argc == 0) {786 /* Note that in repl mode we don't abort on connection error.787 * A new attempt will be performed for every command send. */788 cliConnect(0);789 repl();790 }791 792 /* Otherwise, we have some arguments to execute */793 if (cliConnect(0) != REDIS_OK) exit(1);794 return noninteractive(argc,convertToSds(argc,argv));795 }
转载地址:http://jkczl.baihongyu.com/