上次我们提出了“启动服务器,程序是干什么的?”这个问题,跟着源码,深入了解了Redis服务器的启动过程。现在Redis服务器已经启动,我们需要连接到Redis服务来做一些事情。到这里我们就可以通过redis-cli测试了。既然客户端和服务端都准备好了,那么Redis客户端和服务端如何建立连接呢?服务器如何响应客户端的请求?1.连接到服务器客户端与服务器通信时,第一步是建立连接。接下来我们看一下redis-cli与服务端的连接过程。还记得上次我们使用gdb调试程序吗?我们再用redis-cli来做一遍,看看源码的执行步骤。在开始之前,记得在编辑器中打开redis-cli.c,定位到main函数的位置。毕竟,gdb看代码不像编辑器那样舒服。调试步骤如下:#bashcd/opt/redis-3.2.13//启动Redis服务。Ctrl+c可以启动服务器启动页面,同时保持服务器运行。/src/redis-server--port8379&//Debugredis-clligdb./src/redis-cli#gdb(gdb)bmain(gdb)r-p8379(gdb)layoutsrc(gdb)focuscmd执行以上步骤后,我们会进入如下界面:这时候我们可以回到编辑器页面,看看main函数中哪一行比较有意思,以及然后停下来学习研究。在第2618行,我们将看到执行了parseOptions函数。看名字好像是初始化了一些选项。然后进去看看。1.1初始化客户端配置函数执行步骤:main->parseOptions->main。我们会看到执行redis-cli时携带的参数都是在这个函数中解析出来的。比如我们启动时携带的-p参数会在996行被解析并赋值给客户端的hostport配置项。如下图所示:1.2客户端启动模式函数执行步骤:main.回到main函数,你会看到下面的代码中会有很多cliConnect函数。需要注意的是,这并不意味着redis-cli会多次执行cliConnect函数。实际上,每一个if语句块代表了客户端的一种连接方式。3.2.13版本支持以下模式:Latencymode:延时模式。redis-cli--latency-p8379用于测试客户端和服务器之间的连接延迟。还有--history和--dist选项来显示不同的形式。从机模式:模拟从机节点模式。获取RDB方式:生成并发送RDB持久化文件,保存在本地。管道模式:流水线模式。将命令封装成指定的数据格式,批量发送到redis服务器执行。查找大键:大键的统计分布。Statmode:统计模式。实时显示服务器统计信息。扫描模式:扫描指定模式的按键,相当于扫描模式。LRU测试模式:实时测试LRU算法的命中率。1.3连接服务器函数执行步骤:main->cliConnect->redisConnect->redisContextInit->redisContextConnectTcp->_redisContextConnectTcp->cliConnect。上面我们并没有从一个特殊的模式开始,所以我们会看到cliConnect函数实际上是在2687行被调用的。跟踪进去,让我们看看是如何连接到服务器的。在cliConnect函数中,我们看到根据hostsocket的配置项,会使用不同的连接方式。从名字我们大概可以猜到,一个是TCPSocket连接,一个是原生的UnixSocket连接。如果要使用UnixSocket连接,只需按照格式配置hostscoket:./src/redis-cli-s/tmp/redis.sock。我们这里使用TCPSocket连接,使用redisConnect函数建立连接。继续跟踪,我们会看到上面显示的函数的执行步骤,在_redisContextConnectTcp函数中,我们会看到getaddrinfo和connect函数的调用,这里就是建立TCP连接的地方。1.4检查权限和选择数据库函数执行步骤:cliConnect->anetKeepAlive->cliAuth->cliSelect->main。回到cliConnect函数,如果正常连接服务器,也会将我们上面创建的TCP连接设置为长连接,然后检查权限,选择连接数据库。.../*在Redis上下文套接字中设置积极的KEEP_ALIVE套接字选项*以防止执行长*命令引起的超时。同时,这改进了对真实*错误的检测。*/anetKeepAlive(NULL,context->fd,REDIS_CLI_KEEPALIVE_INTERVAL);/*执行AUTH并选择正确的数据库。*/if(cliAuth()!=REDIS_OK)returnREDIS_ERR;if(cliSelect()!=REDIS_OK)returnREDIS_ERR;...至此,我们运行了客户端与服务端建立连接的全过程。有兴趣的小伙伴可以尝试连接一个不存在的IP或端口,观察程序抛出异常的时机,熟悉整个连接过程。客户端与服务器建立连接后,可以使用相关命令对数据库中的key进行操作。下面以SETKEYVALUE命令为例,看看命令的执行过程。2发送命令请求当用户在客户端输入命令请求时,客户端会根据协议格式对命令请求进行转换,然后将转换后的命令请求通过与服务器相连的socket发送给服务器,如图3显示:因此对于我们上面的命令请求,客户端会变成:"*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n”并将其发送到服务器。以上就是客户端向服务端发送命令的过程。在下一节中,我们将了解服务器如何响应客户端的请求。
