协议是指两个实体(群)之间通信的约定标准,本文主要探讨Redis服务端和客户端交互的协议,其余集群相关的协议留待以后探讨。
协议算是一个必要而伟大的发明。A和B语言不通,但他们可以通过彼此都熟知的方式交流,比如肢体语言,肢体语言在这里就是协议。语言只是交流的一种表现形式,真正的交流与语言无关,就像最早翻译英文的神人,猜想也是用上了肢体语言的吧。除了Redis协议,语言翻译,还有诸如食谱、药方、API都是协议的表现形式,甚至编程语言也可以理解为程序员与机器之间的协议(当然有编译过程)。协议是一种规范,是为了通信双方能在同样的语境下交流,能看得懂,不出错。
Redis协议是基于TCP的,最后都是字节流,一些控制字符加上数据,就是整个协议。(编程语言是关键字加上代码)
(1)简单字符串,首字符是‘+’,其后是字符串内容
(4)定长字符串,首字符是’$’,其后是字符串长度,下面跟字符串,特殊的可以用 “$-1\r\n” 来表示来表示NULL
(5)数组,首字符是’*’,其后是数据长度,下面是数组内容
Redis客户端和服务端通信都基于这五种基本对象,客户端向服务端只会发送定长字符串数据,服务端会根据命令执行结果返回上面的对象类型。比如一个简单的SET命令 “SET a 12″,表示成Redis协议如下:”*3\r\n$3\r\nSET\r\n$1\r\na\r\n$2\r\n12\r\n”,其中 “\r\n” Redis用来分隔每个对象,上传命令服务端的回复是 “+OK\r\n”,表示命令执行成功。
其它的命令可以用tcpdump抓包并用wireshark分析,tcpdump命令是:
sudo tcpdump -nn -i lo0 port 6379 -w wire.cap
然后用wireshark分析包即可,强烈建议实际动手操作一下,对协议的理解大有好处。
协议搞清楚了,下面简单实验一下,调用一下“SET a 12”这个命令。
memset(cbuf, 0, sizeof(cbuf));
cli.sin_family = AF_INET;
cli.sin_port = htons(cPort);
cli.sin_addr.s_addr = inet_addr(“127.0.0.1”);
cClient = socket(AF_INET, SOCK_STREAM, 0);
printf(“socket() failure!\n”);
if (connect(cClient, (struct sockaddr*)&cli, sizeof(cli)) < 0) {
printf(“connect() failure!\n”);
char command[] = “*3\r\n$3\r\nSET\r\n$1\r\na\r\n$2\r\n12\r\n”;
if (send(cClient, command, sizeof(command), 0) == -1) {
printf(“send failure\n”);
cLen = recv(cClient, cbuf, sizeof(cbuf), 0);
if ((cLen < 0) || (cLen == 0)) {
printf(“recv() failure!\n”);
printf(“recv() Data From Server: [%s]\n”, cbuf);
未经允许不得转载:前端撸码笔记 » 从Redis谈起(四)—— Redis协议详解,一个简单的客户端