文章目录
- 一、Redis命令协议
- 二、Java Socket连接
- 三、命令行工具实战
一、Redis命令协议
- Redis客户端和服务器之间通过套接字(socket)进行通信
- 比如客户端向服务器发出 set name www.codecoord.com 命令,将会被转换成以下命令格式发送
*3\r\n$3\r\nSET\r\n$4\r\nname\r\n$17\r\nwww.codecoord.com\r\n
- 下面拆解以下命令格式
- *3:表示命令去掉空格后的命令+参数的数量,比如set name www.codecoord.com就是由set、name、www.codecoord.com三个参数,所以格式为:*3
- \r\n:换行符,从一个参数后每个命令单位都需要使用换行符分隔
- $3:表示即将执行的命令或者参数的长度,此处为set,长度为3,故为$3
- set:set命令
- $4:name参数的长度
- name:set命令需要的key名称
- $17:key参数值的长度
- www.codecoord.com:key参数
- 如果显示换行符,效果会是下面的样子
*3
$3
set
$4
name
$17
www.codecoord.com
- 如果打开持久化文件appendonly.aof,该文件就是保存的该命令协议格式
- 如果现在执行get name命令,协议格式如下
*2\r\n$3\r\nGET\r\n$4\r\nname\r\n
- 符合以上命令协议的命令将会被redis服务器解析,所以我们可以这样做别的事情,比如自己做一个redis客户端等,第三节命令行工具实战将可以实现redis-cli工具的功能
- 测试使用redis命令
127.0.0.1:6379> set name www.codecoord.com
OK
127.0.0.1:6379> get name
"www.codecoord.com"
二、Java Socket连接
- 可以利用Java Socket与Redis服务器连接,如果对Socket使用还不太熟悉的朋友可以先了解一下Socket的相关内容
- Socket伪代码如下
Socket socket = new Socket(IP, Port);
byte[] bytes;
int read;
socket.getOutputStream().write(cmd.toString().getBytes(StandardCharsets.UTF_8));
InputStream stream = socket.getInputStream();
bytes = new byte[Short.MAX_VALUE];
read = stream.read(bytes);
String response = new String(bytes, 0 , read, StandardCharsets.UTF_8);
System.out.println("执行命令:\r\n" + cmd.toString() + " response = " + response);
stream.close();
socket.close();
- 示例代码
package com.codecoord;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class RedisSocketTest {
private static final String SEPARATOR = "\r\n";
public static void main(String[] args) {
socketConnect();
}
private static void socketConnect() {
Socket socket;
try {
socket = new Socket("127.0.0.1", 6379);
} catch (IOException e) {
System.err.println("创建连接失败~");
return;
}
try {
socket.setSoTimeout(3000);
} catch (SocketException e) {
System.err.println("设置超时时间失败~");
return;
}
StringBuilder cmd = new StringBuilder();
cmd.append("*2").append(SEPARATOR);
cmd.append("$3").append(SEPARATOR);
cmd.append("get").append(SEPARATOR);
cmd.append("$4").append(SEPARATOR);
cmd.append("name").append(SEPARATOR);
byte[] bytes;
int read;
try {
socket.getOutputStream().write(cmd.toString().getBytes(StandardCharsets.UTF_8));
InputStream stream = socket.getInputStream();
bytes = new byte[Short.MAX_VALUE];
read = stream.read(bytes);
stream.close();
} catch (Exception e) {
System.err.println("执行命令超时~");
return;
}
String response = new String(bytes, 0 , read, StandardCharsets.UTF_8);
System.out.println("执行命令:\r\n" + cmd.toString());
System.out.println("===========================");
System.out.println("response = " + response);
try {
socket.close();
} catch (IOException e) {
System.err.println("关闭连接异常~");
}
}
}
三、命令行工具实战
- 可以使用Java Socket和Scanner实现redis-cli(客户端命令行工具)
- 实例代码如下
package com.codecoord;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
public class RedisSocketTest {
private static final String SEPARATOR = "\r\n";
private static final String IP = "127.0.0.1";
private static final int PORT = 6379;
public static void main(String[] args) {
commandInput();
}
private static void commandInput() {
Scanner scanner = new Scanner(System.in);
String cmd;
String exit = "bye";
do {
System.out.print(IP + PORT + "> ");
cmd = scanner.nextLine();
if (!exit.equalsIgnoreCase(cmd)) {
parseCommand(cmd);
}
} while (!exit.equalsIgnoreCase(cmd));
System.out.println("退出客户端~");
scanner.close();
}
private static void parseCommand(String command) {
Socket socket;
try {
socket = new Socket(IP, PORT);
} catch (IOException e) {
System.err.println("创建连接失败~");
return;
}
try {
socket.setSoTimeout(3000);
} catch (SocketException e) {
System.err.println("设置超时时间失败~");
return;
}
String[] split = command.split("\\s+");
StringBuilder cmd = new StringBuilder();
cmd.append("*").append(split.length).append(SEPARATOR);
for (String arg : split) {
cmd.append("$").append(arg.length()).append(SEPARATOR);
cmd.append(arg).append(SEPARATOR);
}
InputStream stream;
String[] result;
try {
socket.getOutputStream().write(cmd.toString().getBytes(StandardCharsets.UTF_8));
stream = socket.getInputStream();
byte[] bytes = new byte[Short.MAX_VALUE];
int read = stream.read(bytes);
String response = new String(bytes, 0 , read, StandardCharsets.UTF_8);
result = response.split(SEPARATOR);
} catch (IOException e) {
System.err.println("执行命令超时~");
return;
}
System.out.println(result[result.length - 1]);
try {
stream.close();
socket.close();
} catch (IOException e) {
System.err.println("关闭连接异常~");
}
}
private static void socketConnect() {
Socket socket;
try {
socket = new Socket("127.0.0.1", 6379);
} catch (IOException e) {
System.err.println("创建连接失败~");
return;
}
try {
socket.setSoTimeout(3000);
} catch (SocketException e) {
System.err.println("设置超时时间失败~");
return;
}
StringBuilder cmd = new StringBuilder();
cmd.append("*2").append(SEPARATOR);
cmd.append("$3").append(SEPARATOR);
cmd.append("get").append(SEPARATOR);
cmd.append("$4").append(SEPARATOR);
cmd.append("name").append(SEPARATOR);
byte[] bytes;
int read;
try {
socket.getOutputStream().write(cmd.toString().getBytes(StandardCharsets.UTF_8));
InputStream stream = socket.getInputStream();
bytes = new byte[Short.MAX_VALUE];
read = stream.read(bytes);
stream.close();
} catch (IOException e) {
System.err.println("执行命令超时~");
return;
}
String response = new String(bytes, 0 , read, StandardCharsets.UTF_8);
System.out.println("执行命令:\r\n" + cmd.toString());
System.out.println("===========================");
System.out.println("response = " + response);
try {
socket.close();
} catch (IOException e) {
System.err.println("关闭连接异常~");
}
}
}
- 执行结果
- 127.0.0.16379中间忘记加个:,如果美观点加一下
- 有任何问题可以留言相互交流