redis客户端启动流程
- 用户键入shell命令启动redis客户端:./redis-cli -h ...
- shell fork一个子进程来运行这个程序
- 内核将redis客户端程序src/redis-cli可执行文件从磁盘载入内存
- 子进程通过execvp系统函数来执行与父进程不同的程序,即src/redis-cli程序。
execvp()会从可执行程序中加载代码和静态数据,并用它覆写自己(子进程)的代码段(以及静态数据),堆、栈及其他内存空间也会被重新初始化。然后操作系统就执行该程序,将参数通过 argv 传递给该进程。因此,它并谁有创建新进程,而是直接将当前运行的程序(以前的 shell)替换为不同的运行程序(redis-cli)
调用redis-cli.c中的main函数
程序在子进程中运行直到结束
文章图片
构建RESP格式消息 redis命令行使用的是第三方代码库
linenoise
,等待命令行输入。linenoise是替代readline 功能的命令行工具,其源代码在deps\linenoise目录下。它可以独立于 Redis src 目录下的功能源码进行编译。
【redis客户端发送键消息流程】main()函数首先与向服务器发送connect(),请求建立tcp连接:
int main(int argc, char **argv) {
......
cliConnect(0);
repl();
......
}
等到tcp经过三次握手建好连接后,客户端通过linenoise()函数等待命令行输入:
static void repl(void) {
while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {
......
}
}
(5) repl()中调用hiredis接口redisAppendCommandArgv()根据命令行参数构建RESP格式消息
#0redisAppendCommandArgv () at hiredis.c:965
#1cliSendCommand () at redis-cli.c:1148
#2issueCommandRepeat () at redis-cli.c:1583
#3repl () at redis-cli.c:1764
#4main () at redis-cli.c:7158
// 根据命令行构建resp消息
int redisFormatSdsCommandArgv(){
sds cmd;
cmd = sdsempty();
cmd = sdsMakeRoomFor(cmd, totlen);
/* Construct command */
cmd = sdscatfmt(cmd, "*%i\r\n", argc);
for (j=0;
j < argc;
j++) {
len = argvlen ? argvlen[j] : strlen(argv[j]);
cmd = sdscatfmt(cmd, "$%u\r\n", len);
cmd = sdscatlen(cmd, argv[j], len);
cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1);
}
}
发送redis键命令消息给服务器 发送接口:
调用cliReadReply函数发送数据到服务端并读取服务端的返回数据
cliReadReply() ---> redisGetReply() ---> redisBufferWrite() ---> write()
推荐阅读
- 【Redis 系列】redis 学习九,Redis 的发布和订阅是咋玩的
- 【Redis 系列】redis 学习八,redis 持久化 RDB 和 AOF
- lua|Redis Lua 沙盒逃逸漏洞(CVE-2022-0543)
- Yii2.0 redis的配置和使用
- redis|redis数据类型list总结
- redis|redis数据类型hash总结
- 设置Redis最大占用内存
- javaWeb|redis错误总结
- Redis|彻底解决([ERR] Node is not empty. Either the node already knows other nodes)