• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Java Socket实现Redis客户端的详细说明

    Redis是最常见的缓存服务中间件,在java开发中,一般使用 jedis 来实现。

    如果不想依赖第三方组件,自己实现一个简单的redis客户端工具,该如何实现呢?本文就是介绍这样一种方法。

    Redis的协议非常简单,而且输入数据和输出数据都遵循统一的协议,具体规则参考这里:

    http://redisdoc.com/topic/protocol.html

    Redis的命令协议:

    $参数数量n

    $参数1的值的字节数组长度

    $参数1的值的字符串表示

    $参数2的值的字节数组长度

    $参数2的值的字符串表示

    ...

    $参数n的值的字节数组长度

    $参数n的值的字符串表示

    Redis的返回协议:

    1、状态回复(status reply)的第一个字节是 "+",单行字符串;
    2、错误回复(error reply)的第一个字节是 "-";
    3、整数回复(integer reply)的第一个字节是 ":";
    4、批量回复(bulk reply)的第一个字节是 "$";
    5、多条批量回复(multi bulk reply)的第一个字节是 "*";
    6、所有的命令都是以 \r\n 结尾。

    Java代码说明

    针对上述规则,我们用两个类来实现:

    1、SimpleRedisClient类,主要用于发送请求,并读取响应结果(字符串);

    整体比较简单,稍微复杂点的地方就是读取流数据,遇到两种情况就该结束循环,一是返回长度为-1,二是返回字符串以 \r\n 结尾。

    如果处理不当,可能会导致 read 阻塞,Socket卡住。

    2、SimpleRedisData类,用于解析响应结果,把redis统一协议的字符串,解析为具体的对象。

    这部分代码完全是按照协议规则来实现的,通过一个游标 pos 来向前移动,在移动过程中识别不同格式的数据。

    最复杂的是 list 类型的数据,以 * 开头,后面跟着一个整数,表示列表中所有元素的数量,然后就是每一个列表元素的值,循环解析即可。

    package demo;
    
    import java.io.Closeable;
    import java.io.IOException;
    import java.net.Socket;
    import java.util.List;
    
    public class SimpleRedisClient implements Closeable {
    
        private String host;
        private int port;
        private String auth;
        private Socket socket = null;
    
        public SimpleRedisClient(String host, int port, String auth) {
            this.host = host;
            this.port = port;
            this.auth = auth;
    
            try {
                socket = new Socket(this.host, this.port);
                socket.setSoTimeout(8 * 1000);//8秒
            } catch (Exception ex) {
                socket = null;
                ex.printStackTrace();
            }
        }
    
        public boolean connect() throws IOException {
            if (socket == null || auth == null || auth.length() = 0) {
                return false;
            }
            String response = execute("AUTH", auth);
            if (response == null || response.length() = 0) {
                return false;
            }
            String res = new SimpleRedisData(response).getString();
            return "OK".compareTo(res) == 0;
        }
    
        @Override
        public void close()  {
            try {
                if (socket != null) {
                    socket.shutdownOutput();
                    socket.close();
                }
                //System.out.println("closed");
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
        public String getString(String key) {
            if (socket == null || key == null || key.isEmpty()) {
                return null;
            }
            try {
                String response = execute("GET", key);
                return new SimpleRedisData(response).getString();
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
    
        public String setString(String key, String value) {
            if (socket == null || key == null || key.isEmpty()) {
                return null;
            }
            try {
                String response = execute("SET", key, value);
                return new SimpleRedisData(response).getString();
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
    
        public String deleteKey(String key) throws IOException {
            if (socket == null || key == null || key.isEmpty()) {
                return null;
            }
            String response = execute("DEL", key);
            return new SimpleRedisData(response).getString();
        }
    
        public ListString> getKeys(String pattern) throws IOException {
            if (socket == null || pattern == null || pattern.isEmpty()) {
                return null;
            }
    
            String response = execute("KEYS", pattern);
            return new SimpleRedisData(response).getStringList();
        }
    
        public String execute(String... args) throws IOException {
            if (socket == null || args == null || args.length = 0) {
                return null;
            }
    
            //System.out.println(StringUtil.join(args, " "));
    
            StringBuilder request = new StringBuilder();
            request.append("*" + args.length).append("\r\n");//参数的数量
    
            for (int i = 0; i  args.length; i++) {
                request.append("$" + args[i].getBytes("utf8").length).append("\r\n");//参数的长度
                request.append(args[i]).append("\r\n");//参数的内容
            }
    
            socket.getOutputStream().write(request.toString().getBytes());
            socket.getOutputStream().flush();
    
            StringBuilder reply = new StringBuilder();
            int bufSize = 1024;
            while (true) {
                byte[] buf = new byte[bufSize];
                int len = socket.getInputStream().read(buf);
                if (len  0) {
                    break;
                }
                String str = new String(buf, 0, len);
                reply.append(str);
                if (str.endsWith("\r\n")) {
                    break;
                }
            }
    
            String response = reply.toString();
            //System.out.println("response: " + response);
            return response;
        }
    
    
    }
    package demo;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class SimpleRedisData {
    
        public SimpleRedisData(String rawData) {
            this.rawData = rawData;
            //System.out.println(rawData);
        }
    
        private int pos;
        private String rawData;
    
        public String getString() {
            if (rawData == null || rawData.length() = 0) {
                return null;
            }
            int i = rawData.indexOf("\r\n", pos);
            if (i = 0) {
                return null;
            }
            char c = rawData.charAt(pos);
            if (c == '+') {
                int from = pos + 1;
                int to = i;
                String v = rawData.substring(from, to);
                pos = to + 2;
                return v;
            } else if (c == '-') {
                int from = pos + 1;
                int to = i;
                String v = rawData.substring(from, to);
                pos = to + 2;
                return v;
            } else if (c == ':') {
                int from = pos + 1;
                int to = i;
                String v = rawData.substring(from, to);
                pos = to + 2;
                return v;
            } else if (c == '$') {
                int from = pos + 1;
                int to = i;
                int bulkSize = Integer.parseInt(rawData.substring(from, to));
                pos = to + 2;
    
                from = pos;
                to = pos + bulkSize;
                try {
                    //$符号后面的数值是指内容的字节长度,而不是字符数量,所以要转换为二进制字节数组,再取指定长度的数据
                    byte[] buf = rawData.substring(from).getBytes("utf-8");
                    String v = new String(buf, 0, bulkSize);
                    pos = to + 2;
                    return v;
                } catch (Exception ex) {
                    ex.printStackTrace();
                    return null;
                }
            } else {
                return null;
            }
        }
    
        public ListString> getStringList() {
            if (rawData == null || rawData.length() = 0) {
                return null;
            }
            int i = rawData.indexOf("\r\n", pos);
            if (i = 0) {
                return null;
            }
            char c = rawData.charAt(pos);
            if (c == '*') {
                ListString> values = new ArrayList>();
                int from = pos + 1;
                int to = i;
                int multSize = Integer.parseInt(rawData.substring(from, to));
                pos = to + 2;
                for (int index = 0; index  multSize; index++) {
                    values.add(getString());
                }
                return values;
            } else {
                return null;
            }
        }
    
    }
    package demo;
    
    import org.junit.jupiter.api.Test;
    
    import java.util.List;
    
    public class RedisTest {
    
        @Test
        public void test() {
            SimpleRedisClient client = null;
            try {
                client = new SimpleRedisClient("127.0.0.1", 6379, "123456");
                System.out.println("connected: " + client.connect());
    
                ListString> keyList = client.getKeys("api_*");
    
                for (int i = 0; i  keyList.size(); i++) {
                    System.out.println((i + 1) + "\t" + keyList.get(i));
                }
    
               System.out.println("keys: " + keyList != null ? keyList.size() : "null");
    
               System.out.println(client.getString("api_getCustomerName"));
    
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                if (client != null) {
                    client.close();
                }
            }
        }
    
    }

    优点:

    1、不依赖任何第三方组件,可以顺利编译通过;

    2、代码极其简单。

    不足之处:

    1、未考虑并发访问;

    2、未提供更多的数据类型,以及读写方法,大家可以在此基础上包装一下。

    以上就是如何用Java Socket实现一个简单的Redis客户端的详细内容,更多关于Java Socket Redis客户端的资料请关注脚本之家其它相关文章!

    您可能感兴趣的文章:
    • Java Socket+多线程实现多人聊天室功能
    • Java Socket实现多人聊天系统
    • Java Socket模拟实现聊天室
    • java Nio使用NioSocket客户端与服务端交互实现方式
    • 浅谈java socket的正确关闭姿势
    • 解决java.net.SocketTimeoutException: Read timed out的问题
    • 详解Java Socket通信封装MIna框架
    • Java使用Socket简单通讯详解
    上一篇:redis实现共同好友的思路详解
    下一篇:redis哨兵常用命令和监控示例详解
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Java Socket实现Redis客户端的详细说明 Java,Socket,实现,Redis,客户端,