1.Redis网络通信协议
Redis底层网络通信协议其实是通过TCP来完成的。
2.Redis通信协议
Redis的通信协议首先是以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下:
(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。
(-) 表示一个错误信息,具体信息是当前行-后面的字符。
(*) 表示消息体总共有多少行,不包括当前行,*后面是具体的行数。
()表示下一行数据长度,不包括换行符长度\r\n,)表示下一行数据长度,不包括换行符长度\r\n,后面则是对应的长度的数据。
( : ) 表示返回一个数值,:后面是相应的数字节符。
举个例子:
set demo 123456
*3\r\n #消息一共有三行
$3\r\n #第一行有字节数为3
set\r\n #第一行的消息
$4\r\n #第二行字节数为4
demo\r\n #第二行的消息
$6\r\n #第三行字节数为6
123456\r\n #第三行的消息
+OK\r\n #操作成功
3.Redis通信协议实现
set
public static void main(String[] args) throws Exception {
// socket
Socket socket = new Socket("140.143.135.210", 6379);
// oi流
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
// 向redis服务器写
os.write("set demo 123456\r\n".getBytes());
//从redis服务器读,到bytes中
byte[] bytes = new byte[1024];
int len = is.read(bytes);
// to string 输出一下
System.out.println(new String(bytes,0,len));
}
get
public static void main(String[] args) throws Exception {
// socket
Socket socket = new Socket("140.143.135.310", 6379);
// oi流
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
// 向redis服务器写
os.write("get demo\r\n".getBytes());
//从redis服务器读,到bytes中
byte[] bytes = new byte[1024];
int len = is.read(bytes);
// to string 输出一下
System.out.println(new String(bytes,0,len));
}
刚才客户端向服务端发送的 “get demo” , 这种只是"内联命令", 而不是Redis真正的通信协议.
-
问: 什么意思呢? 答: 就是说你可以像之前那样给服务端发, 服务器端接受到后, 会遍历一遍你发送的内容, 最后根据空格来分析你所发的内容的含义.
-
问: 这样有什么不好的吗? 答: 如果这样的话, 你就把解析的工作交给了服务器来做, 会加大服务器的工作量.
-
问: 那怎么样才是符合规范的呢? 符合协议的话真的会提高服务器的效率? 答: 首先看一下符合协议的客户端和服务端之间的交互把
例: set java python ,抓到包之后是这样的:
红色是客户端发送的内容, 蓝色是服务器端返回的内容.
咱们一起解析一下:
*3表示 , 客户端即将发送3段内容
哪三段呢? 第一段:
$3 SET
第二段:$4 java'
第三段:$6 python
更严格地说: 第一段:
$3\r\nSET\r\n
第二段:$4\r\njava\r\n
第三段:$6\r\npython\r\n
$符号的意思在上一小节就已经提到过了, 表示下文的内容的长度, 方便服务器进行读取.
例如:
$6
就已经把python的长度给汇报出来了, 服务器只需要截取区间[index, index+6]就好了, 不需要去找空格在什么地方(找空格的时间复杂度是O(n), 而$6这种写法是O(1) )
4 Jedis呢
其实Jedis做的工作大体就是把SET key value 这样的格式转化为下面这种格式, 然后发到Redis服务端:
*3\r\n
$3\r\n
SET\r\n
$3\r\n
key\r\n
$5\r\n
value\r\n