redis 官网:https://redis.io/
jedis的用法,可以在redis的官网最上边一栏的客户端里面就可以找到。
jedis客户端连接redis服务端的大概流程是这样的。
- 传输层:用于建立与redis的网络通信,传输信息。起到连接的作用
- 消息协议层:与redis确认RESP协议是否正确,并携带所要传递的数据信息。
- api操作层:封装客户端api,方便其他人调用。
/**
*
* @ClassName: Connection
* @Description: redis源码学习 之 徒手写redis get、set方法
* @author hsd
* @date 2019年3月7日
*
*/
public class Connection {
private Socket socket;
private String host;
private int port;
private OutputStream out;
private InputStream in;
public Connection(String host,int port){
this.port = port;
this.host = host;
}
public Connection connection(){
try {
socket = new Socket(host,port);
in = socket.getInputStream();
out = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return this;
}
/**
*
*@Title: sendcommand
* @Description: 连接redis服务器端 发送数据和命令
* @param: @return
* @return: Connection
* @throws
*/
public Connection sendcommand(Protocol.Command command,byte[] ... args){
connection();
Protocol.sendCommand(out, command, args);
return this;
}
/**
*
*@Title: getStatusCodereply
* @Description: 获取redis返回给jedis客户端的状态码
* @param: @return
* @return: String
* @throws
*/
public String getStatusCodereply(){
byte[] bytes = new byte[1024];
try {
socket.getInputStream().read(bytes);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new String(bytes);
}
}
/**
*
* @ClassName: Client
* @Description: 对外提供api接口的类
* @author hsd
* @date 2019年3月7日
*
*/
public class Client {
private Connection connect;
public Client(String host,int port){
this.connect = new Connection(host, port);
}
public String set(String key,String value){
connect.sendcommand(Protocol.Command.SET,key.getBytes(),value.getBytes());
return connect.getStatusCodereply();
}
public String get(String key){
connect.sendcommand(Protocol.Command.GET,key.getBytes());
return connect.getStatusCodereply();
}
}
/**
*
* @ClassName: Protocol
* @Description: jedis和redis之间的通讯协议
* @author hsd
* @date 2019年3月7日
*
*/
public class Protocol {
/**
* 创建jedis和redis的通讯协议 resp
*/
public static final String DOLLAR_BYTE="$";
public static final String ASTERISK_BYTE="*";
public static final String BLACK_BYTE="\r\n";
/**
*
*@Title: sendCommand
* @Description: 拼接、组装数据发送给redis
* @param:
* @return: void
* @throws
*/
public static void sendCommand(OutputStream os,Command command,byte[] ... args){
StringBuilder sb = new StringBuilder();
sb.append(ASTERISK_BYTE).append(args.length+1).append(BLACK_BYTE);
sb.append(DOLLAR_BYTE).append(command.name().length()).append(BLACK_BYTE);
sb.append(command.name()).append(BLACK_BYTE);
for(final byte[] arg : args){
sb.append(DOLLAR_BYTE).append(arg.length).append(BLACK_BYTE);
sb.append(new String(arg)).append(BLACK_BYTE);
}
try {
os.write(sb.toString().getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*
* @ClassName: Command
* @Description: 创建一个枚举,用于确定发送消息的类型 是get 还是 set还是key 等等。。。。。
* @author 胡少东
* @date 2019年3月7日
*
*/
public static enum Command{
GET,SET,KEYS
}
}
/**
*
* @ClassName: JedisClientTest
* @Description: TODO(reids的java客戶端的练习)
* @author hsd
* @date 2019年3月7日
*
*/
public class JedisClientTest {
public static void main(String[] args) {
// Jedis jedis = new Jedis("127.0.0.1",10001);
//
// jedis.set("kobe", "kobe");
//
// System.out.println(jedis.get("kobe"));
Client jedis = new Client("127.0.0.1",6379);
jedis.set("kobe", "kobe-branty");
System.out.println(jedis.set("kobe", "kobe-branty"));
System.out.println(jedis.get("kobe"));
}
}
/**
*
* @ClassName: Hack
* @Description: 黑客技术,模拟redis服务端,拦截到jedis发送的请求,查看传输协议。
* @author hsd
* @date 2019年3月7日
*
*/
public class Hack {
public static void main(String[] args) {
try {
ServerSocket ss = new ServerSocket(10001);
Socket socket = ss.accept();
byte[] bytes = new byte[1024];
socket.getInputStream().read(bytes);
System.out.println(new String(bytes));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
开发是的先后顺序是:
- api操作层:Client
- 消息协议层:Protocol
- 传输层:Connection
- 消息协议层需要模拟redis服务器,获取jedis发送的协议:Hack