Redis(八):Jedis原理

由于Redis是C语言写的,java语言要与C语言交互的方式JNI或网络通信。java 提供的Jedis客户端,操作Redis。

Jedis源码地址:https://github.com/xetorthio/jedis

redis是典型的cs架构。cs就会涉及到网络通信/通信协议。java使用socket,协议为Redis的RESP协议。

RESP请求协议

Redis Serialization Protocol (Redis序列化协议)

  • 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 。
  • 客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾。
  • 在这个协议中, 所有发送至 Redis 服务器的参数都是二进制安全(binary safe)的。
    *<参数数量> CR LF
    $<参数 1 的字节数量> CR LF
    <参数 1 的数据> CR LF
    ...
    $<参数 N 的字节数量> CR LF
    <参数 N 的数据> CR LF

    示例:

redis> SET mykey "Hello"

实际本质发送的请求数据为:

*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nHello\r\n

#格式化:
*3
$3
SET
$5
mykey
$5
Hello

RESP返回协议:

#RESP有五种最小的单元类型,单元结束时统一加上回车换行符号\r\n。
For Simple Strings the first byte of the reply is "+"
For Errors the first byte of the reply is "-"
For Integers the first byte of the reply is ":"
For Bulk Strings the first byte of the reply is "$"
For Arrays the first byte of the reply is "*"

#翻译为:
单行字符串 以 + 符号开头。
多行字符串 以 $ 符号开头,后跟字符串长度。
整数值 以 : 符号开头,后跟整数的字符串形式。
错误消息 以 - 符号开头。
数组 以 * 号开头,后跟数组的长度。

实际收到的响应数据:

+OK\r\n

#其他回复
状态回复(status reply)的第一个字节是 “+”
错误回复(error reply)的第一个字节是 “-“
整数回复(integer reply)的第一个字节是 “:”
批量回复(bulk reply)的第一个字节是 “$”
多条批量回复(multi bulk reply)的第一个字节是 “*”

Jedis原理

当知道HTTP协议格式后,我们可以使用SOCKET模拟HTTP协议请求。无非就是使用JAVA按照HTTP协议格式拼接字符串,利用SOCKET进行数据传输而已。

Jedis也是同理。按照RESP协议格式,拼接数据,使用scoket进行数据传输。

public class Client {

    public static final String ENCODE = "UTF-8";


    private Connection connection = new Connection();

    public String set(String key, String value) throws Exception {

        byte[] keyBytes = key.getBytes(ENCODE);
        byte[] valueBytes = value.getBytes(ENCODE);

        byte[][] bytes = {keyBytes, valueBytes};

        connection.sendCommand(Protocol.Command.SET, bytes);
        return connection.getResult();
    }


    public String get(String key) throws Exception {
        this.connection.sendCommand(Protocol.Command.GET, key.getBytes(ENCODE));
        return connection.getResult();
    }

    //测试
    public static void main(String[] args) throws Exception {

        Client client = new Client();
        System.out.println(client.set("name", "value2"));
        System.out.println(client.get("name"));
    }

}
public class Connection {
    private Socket socket;

    private String host = "127.0.0.1";
    private int port = 6379;

    private OutputStream outputStream;
    private InputStream inputStream;


    //发送命令
    public Connection sendCommand(Protocol.Command cmd, byte[]... args) throws IOException {
        this.connect();
        Protocol.sendCommand(this.outputStream, cmd, args);
        return this;
    }

    //建立scoket 连接
    public void connect() throws IOException {
        socket = new Socket(host, port);
        inputStream = socket.getInputStream();
        outputStream = socket.getOutputStream();
    }


    //获取返回信息
    public String getResult() throws IOException {
        byte b[] = new byte[1024];
        socket.getInputStream().read(b);
        return new String(b);
    }
}
public class Protocol {

    public static final String PARAM_BYTE_NUM = "$";
    public static final String PARAM_NUM = "*";
    public static final String TERMINATION = "\r\n";


    public static void sendCommand(OutputStream outputStream, Command command, byte[]... b) {
        /*
            *3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nHello\r\n
                #格式化:
                *3
                $3
                SET
                $5
                mykey
                $5
                Hello
        */
        StringBuffer sb = new StringBuffer();
        sb.append(PARAM_NUM).append(b.length + 1).append(TERMINATION);
        sb.append(PARAM_BYTE_NUM).append(command.name().length()).append(TERMINATION);
        sb.append(command).append(TERMINATION);
        for (byte[] arg : b) {
            sb.append(PARAM_BYTE_NUM).append(arg.length).append(TERMINATION);
            sb.append(new String(arg)).append(TERMINATION);
        }
        try {
            outputStream.write(sb.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static enum Command {
        SET,
        GET;
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值