最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java Socket實(shí)現(xiàn)Redis客戶端的詳細(xì)說明

 更新時(shí)間:2021年05月26日 16:13:20   作者:卡卡西村長(zhǎng)的小灶  
socket編程是一門技術(shù),它主要是在網(wǎng)絡(luò)通信中經(jīng)常用到.這篇文章主要介紹了如何用Java Socket實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Redis客戶端,需要的朋友可以參考下

Redis是最常見的緩存服務(wù)中間件,在java開發(fā)中,一般使用 jedis 來實(shí)現(xiàn)。

如果不想依賴第三方組件,自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單的redis客戶端工具,該如何實(shí)現(xiàn)呢?本文就是介紹這樣一種方法。

Redis的協(xié)議非常簡(jiǎn)單,而且輸入數(shù)據(jù)和輸出數(shù)據(jù)都遵循統(tǒng)一的協(xié)議,具體規(guī)則參考這里:

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

Redis的命令協(xié)議:

$參數(shù)數(shù)量n

$參數(shù)1的值的字節(jié)數(shù)組長(zhǎng)度

$參數(shù)1的值的字符串表示

$參數(shù)2的值的字節(jié)數(shù)組長(zhǎng)度

$參數(shù)2的值的字符串表示

...

$參數(shù)n的值的字節(jié)數(shù)組長(zhǎng)度

$參數(shù)n的值的字符串表示

Redis的返回協(xié)議:

1、狀態(tài)回復(fù)(status reply)的第一個(gè)字節(jié)是 "+",單行字符串;
2、錯(cuò)誤回復(fù)(error reply)的第一個(gè)字節(jié)是 "-";
3、整數(shù)回復(fù)(integer reply)的第一個(gè)字節(jié)是 ":";
4、批量回復(fù)(bulk reply)的第一個(gè)字節(jié)是 "$";
5、多條批量回復(fù)(multi bulk reply)的第一個(gè)字節(jié)是 "*";
6、所有的命令都是以 \r\n 結(jié)尾。

Java代碼說明

針對(duì)上述規(guī)則,我們用兩個(gè)類來實(shí)現(xiàn):

1、SimpleRedisClient類,主要用于發(fā)送請(qǐng)求,并讀取響應(yīng)結(jié)果(字符串);

整體比較簡(jiǎn)單,稍微復(fù)雜點(diǎn)的地方就是讀取流數(shù)據(jù),遇到兩種情況就該結(jié)束循環(huán),一是返回長(zhǎng)度為-1,二是返回字符串以 \r\n 結(jié)尾。

如果處理不當(dāng),可能會(huì)導(dǎo)致 read 阻塞,Socket卡住。

2、SimpleRedisData類,用于解析響應(yīng)結(jié)果,把redis統(tǒng)一協(xié)議的字符串,解析為具體的對(duì)象。

這部分代碼完全是按照協(xié)議規(guī)則來實(shí)現(xiàn)的,通過一個(gè)游標(biāo) pos 來向前移動(dòng),在移動(dòng)過程中識(shí)別不同格式的數(shù)據(jù)。

最復(fù)雜的是 list 類型的數(shù)據(jù),以 * 開頭,后面跟著一個(gè)整數(shù),表示列表中所有元素的數(shù)量,然后就是每一個(gè)列表元素的值,循環(huán)解析即可。

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 List<String> 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");//參數(shù)的數(shù)量

        for (int i = 0; i < args.length; i++) {
            request.append("$" + args[i].getBytes("utf8").length).append("\r\n");//參數(shù)的長(zhǎng)度
            request.append(args[i]).append("\r\n");//參數(shù)的內(nèi)容
        }

        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 {
                //$符號(hào)后面的數(shù)值是指內(nèi)容的字節(jié)長(zhǎng)度,而不是字符數(shù)量,所以要轉(zhuǎn)換為二進(jìn)制字節(jié)數(shù)組,再取指定長(zhǎng)度的數(shù)據(jù)
                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 List<String> 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 == '*') {
            List<String> 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());

            List<String> 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();
            }
        }
    }

}

優(yōu)點(diǎn):

1、不依賴任何第三方組件,可以順利編譯通過;

2、代碼極其簡(jiǎn)單。

不足之處:

1、未考慮并發(fā)訪問;

2、未提供更多的數(shù)據(jù)類型,以及讀寫方法,大家可以在此基礎(chǔ)上包裝一下。

以上就是如何用Java Socket實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Redis客戶端的詳細(xì)內(nèi)容,更多關(guān)于Java Socket Redis客戶端的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 深入解析Redis的LRU與LFU算法實(shí)現(xiàn)

    深入解析Redis的LRU與LFU算法實(shí)現(xiàn)

    這篇文章主要重點(diǎn)介紹了Redis的LRU與LFU算法實(shí)現(xiàn),并分析總結(jié)了兩種算法的實(shí)現(xiàn)效果以及存在的問題,并闡述其優(yōu)劣特性,感興趣的小伙伴跟著小編一起來看看吧
    2023-07-07
  • Redis中HyperLogLog的使用詳情

    Redis中HyperLogLog的使用詳情

    這篇文章主要介紹了Redis中HyperLogLog的使用詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • Redis中緩存預(yù)熱與緩存穿透解決方案

    Redis中緩存預(yù)熱與緩存穿透解決方案

    Redis緩存預(yù)熱與緩存穿透是Redis緩存使用中的兩個(gè)重要概念,文章首先介紹了Redis緩存預(yù)熱和緩存穿透的基本概念,然后詳細(xì)闡述了它們的產(chǎn)生原因和解決方案,感興趣的可以了解一下
    2023-12-12
  • Redis出現(xiàn)(error)NOAUTH?Authentication?required.報(bào)錯(cuò)的解決辦法(秒懂!)

    Redis出現(xiàn)(error)NOAUTH?Authentication?required.報(bào)錯(cuò)的解決辦法(秒懂!)

    這篇文章主要給大家介紹了關(guān)于Redis出現(xiàn)(error)NOAUTH?Authentication?required.報(bào)錯(cuò)的解決辦法,對(duì)于 這個(gè)錯(cuò)誤這通常是因?yàn)镽edis服務(wù)器需要密碼進(jìn)行身份驗(yàn)證,但客戶端沒有提供正確的身份驗(yàn)證信息導(dǎo)致的,需要的朋友可以參考下
    2024-03-03
  • 使用redis實(shí)現(xiàn)附近的人功能

    使用redis實(shí)現(xiàn)附近的人功能

    這篇文章主要介紹了使用redis實(shí)現(xiàn)附近的人,實(shí)現(xiàn)諸如附近的人這類依賴于地理位置信息的功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2021-09-09
  • 從源碼解讀redis持久化

    從源碼解讀redis持久化

    redis的持久化也就是數(shù)據(jù)落地,對(duì)于任何一個(gè)數(shù)據(jù)系統(tǒng)都要考慮是不是需要數(shù)據(jù)落地。在系統(tǒng)崩潰或是機(jī)房掉電等的情況下,將有用的數(shù)據(jù)記錄在非易失性存儲(chǔ)器上面,防止數(shù)據(jù)丟失,以及用來系統(tǒng)重啟時(shí)的數(shù)據(jù)恢復(fù)。
    2018-08-08
  • Redis過期鍵與內(nèi)存淘汰策略深入分析講解

    Redis過期鍵與內(nèi)存淘汰策略深入分析講解

    因?yàn)閞edis數(shù)據(jù)是基于內(nèi)存的,然而內(nèi)存是非常寶貴的資源,然后我們就會(huì)對(duì)一些不常用或者只用一次的數(shù)據(jù)進(jìn)行存活時(shí)間設(shè)置,這樣才能提高內(nèi)存的使用效率,下面這篇文章主要給大家介紹了關(guān)于Redis中過期鍵與內(nèi)存淘汰策略,需要的朋友可以參考下
    2022-11-11
  • 淺析Redis Sentinel 與 Redis Cluster

    淺析Redis Sentinel 與 Redis Cluster

    本文主要介紹Redis Sentinel 及 Redis Cluster的區(qū)別及用法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • redis熱key問題怎樣解決

    redis熱key問題怎樣解決

    這篇文章主要介紹了redis熱key問題怎樣解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • Redis key命令key的儲(chǔ)存方式

    Redis key命令key的儲(chǔ)存方式

    這篇文章主要介紹了Redis key命令key的儲(chǔ)存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04

最新評(píng)論

大荔县| 万宁市| 兴宁市| 嘉义县| 冀州市| 洮南市| 宣城市| 固阳县| 瑞安市| 英山县| 中方县| 隆安县| 惠州市| 开封市| 正蓝旗| 德格县| 新余市| 温泉县| 平顺县| 喜德县| 南陵县| 吉木乃县| 新野县| 崇文区| 兰州市| 合川市| 凤凰县| 石家庄市| 湘阴县| 互助| 柳州市| 阿克苏市| 贵州省| 德化县| 大理市| 启东市| 巫山县| 泽普县| 淮南市| 淮阳县| 双桥区|