這份代碼是redis的client接口,其和server端的交互使用了deps目錄下的hiredis c庫,同時,在這部分代碼中,應(yīng)用了linenoise庫完成類似history命令查詢、自動補全等終端控制功能。
1
#include
"
fmacros.h
" //用于mac下的兼容性處理
2
#include
"
version.h
" //版本信息頭文件,當(dāng)前版本是2.4.10
3
4
#include <stdio.h>
5
#include <
string
.h>
6
#include <stdlib.h>
7
#include <unistd.h>
8
#include <ctype.h>
9
#include <errno.h>
10
#include <sys/stat.h>
11
#include <sys/time.h>
12
#include <assert.h>
13
14
#include
"
hiredis.h
" //redis 客戶端庫的頭文件
15
#include
"
sds.h
"
16
#include
"
zmalloc.h
"
17
#include
"
linenoise.h
" //終端控制庫的頭文件
18
#include
"
help.h
" //當(dāng)前所有的命令文件匯總,用于tab自動補全功能的源數(shù)據(jù)
/* help entry的結(jié)構(gòu)如下:
struct commandHelp {
20 char *name; ? ? ? ? ?//命令名字
21 char *params; ? ? ? ?//參數(shù)格式
22 char *summary; ? ? ? //簡單的解釋信息
23 int group; ? ? ? ? ? //命令類型(當(dāng)前版本共分10種不同類型的命令)
24 char *since; ? ? ? ? //從哪個版本開始支持此命令
25 } */
19
20
#define
REDIS_NOTUSED(V) ((void) V)
21
22
static
redisContext *
context; //維護(hù)client和server端的連接信息,包括文件描述符,錯誤信息等,參見deps/hiredis/hiredis.h
23
static
struct
config {
24
char
*
hostip;
25
int
hostport;
26
char
*
hostsocket;
27
long
repeat; //命令重復(fù)執(zhí)行次數(shù)
28
long
interval; //命令重復(fù)執(zhí)行間隔
29
int
dbnum; // db no.
30
int
interactive; //交互模式 or 命令模式
31
int
shutdown;
32
int
monitor_mode; //監(jiān)控模式
33
int
pubsub_mode; //pub sub模式
34
int
latency_mode; //該模式測試cli到server執(zhí)行ping命令的時間間隔(應(yīng)用層ping)
35
int
stdinarg;
/*
get last arg from stdin. (-x option)
*/
36
char
*
auth; //需要鑒權(quán)時的密碼信息
37
int
raw_output;
/*
output mode per command
*/ //選擇該模式,將不會添加類似(interger),參見
http://blog.sina.com.cn/s/blog_6262a50e0100zw83.html
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 @<group>\" to get a list of commands in <group>\r\n
"
154
"
\"help <command>\" for help on <command>\r\n
"
155
"
\"help <tab>\" to get a list of possible help topics\r\n
"
156
"
\"quit\" to exit\r\n
"
,
157
version
158
);
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 / parsing
237
*---------------------------------------------------------------------------
*/
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 performed
266
* 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
else
283
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 want
318
* 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 parent
352
* 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 interface
507
*---------------------------------------------------------------------------
*/
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 <hostname> Server hostname (default: 127.0.0.1)\n
"
588
"
-p <port> Server port (default: 6379)\n
"
589
"
-s <socket> Server socket (overrides hostname and port)\n
"
590
"
-a <password> Password to use when connecting to the server\n
"
591
"
-r <repeat> Execute specified command N times\n
"
592
"
-i <interval> When -r is used, waits <interval> seconds per command.\n
"
593
"
It is possible to specify sub-second times like -i 0.1.\n
"
594
"
-n <db> Database number\n
"
595
"
-x Read last argument from STDIN\n
"
596
"
-d <delimiter> 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 4096
628
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
}
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

