一、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中间忘记加个:,如果美观点加一下 有任何问题可以留言相互交流