Reids通信协议
第四章 Redis通信协议
概要
Redis通信
1. Redis通信协议
Redis 通信协议是客户端与 Redis 服务器之间进行交互的规则和约定;
简介:Redis 采用的是 RESP(Redis Serialization Protocol)协议,它是一种简单的文本协议,具有良好的可读性和可扩展性,能够高效地在客户端和服务器之间传输数据。
6.0以后新增RESP3协议,但是默认使用是RESP2。
/* 根据客户端协议版本发送响应 */
void addReply(client *c, robj *obj) {
if (c->resp == 3) {
/* 使用RESP3格式发送 */
sendReplyUsingRESP3(c, obj);
} else {
/* 使用RESP2格式发送 */
sendReplyUsingRESP2(c, obj);
}
}
1.RESP2
/* RESP2 类型标识字符 */
#define REDIS_REPLY_STRING '+'
#define REDIS_REPLY_ERROR '-'
#define REDIS_REPLY_INTEGER ':'
#define REDIS_REPLY_BULK '$'
#define REDIS_REPLY_MULTI '*'
Redis 通过processInputBuffer()函数处理客户端输入,根据首个字节判断协议类型:
/* 处理客户端输入缓冲区 */
void processInputBuffer(client *c) {
/* ... */
if (c->resp == 3) {
/* RESP3 解析逻辑 */
if (processRESP3Packet(c) != C_OK) break;
} else {
/* RESP2 解析逻辑 */
if (processRESP2Packet(c) != C_OK) break;
}
/* ... */
}
2.RESP2数据类型
- 简单字符串(Simple Strings)
格式:以+开头,后跟字符串内容,以\r\n结尾。
用途:用于返回简单的成功消息,如OK。
示例:“+OK\r\n”
- 错误(Errors)
格式:以-开头,后跟错误信息,以\r\n结尾。
用途:返回命令执行过程中的错误。
示例:-ERR unknown command ‘foobar’\r\n - 整数数值(Integers)
格式:以:开头,后跟整数值,以\r\n结尾。
用途:返回计数结果(如INCR命令)或状态码(如EXISTS返回1或0)。
示例:“:42\r\n”
- 多行字符串(Bulk Strings)
格式:以$开头,后跟字符串长度(字节数),再以\r\n分隔,接着是实际字符串内容,最后以\r\n结尾。,
示例:
字符串hello:“$5\r\nhello\r\n”
空字符串:“$0\r\n\r\n”
- 数组(Arrays)
格式:
以*开头,后跟数组元素个数,以\r\n分隔,每个元素遵循上述任意数据类型格式。
空数组:“*0\r\n”
空值数组:“*-1\r\n”
(表示NULL数组)。
示例:
3.基于socket的自定义客户端
基于socket的自定义客户端
private static Socket socket;
private static PrintWriter writer;
private static BufferedReader reader;
public static void main(String[] args) {
try {
//1. 建立连接
socket = new Socket("localhost",6379);
//2. 获取输入/出流
writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
//3. 请求
sendRequest("set","name","HelloWorld");
sendRequest("mget","name","msg");
//4. 响应
Object response = response();
System.out.println(response);
} catch (IOException e) {
e.printStackTrace();
}finally {
}
}
private static void sendRequest(String ... args){
writer.println("*" +args.length);
for (String arg : args) {
writer.println("$" + arg.getBytes(StandardCharsets.UTF_8).length);
writer.println(arg);
}
writer.flush();
}
private static Object response() throws IOException {
int read = reader.read();
switch (read){
case '+':
return reader.readLine();
case '-':
throw new RuntimeException(reader.readLine());
case ':':
return Long.parseLong(reader.readLine());
case '$':
int len = Integer.parseInt(reader.readLine());
if (len == -1 ){
return null;
}
if (len == 0){
return "";
}
return reader.readLine();
case '*':
int l = Integer.parseInt(reader.readLine());
if (l <= 0) {
return null;
}
ArrayList<Object> list = new ArrayList<>(l);
for (int i = 0; i < l; i++) {
list.add(response());
}
default:
throw new RuntimeException("ERROR ");
}
}