自己動(dòng)手寫一個(gè)能操作redis的客戶端-創(chuàng)新互聯(lián)

作者:孤獨(dú)煙 來源:微信訂閱號(hào)(程序員孤獨(dú)煙)

原文鏈接: https://mp.weixin.qq.com/s/IBynkex-FHhvJ3tmizvJhA

站在用戶的角度思考問題,與客戶深入溝通,找到蘇州網(wǎng)站設(shè)計(jì)與蘇州網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名申請(qǐng)、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋蘇州地區(qū)。

引言

redis大家在項(xiàng)目中經(jīng)常會(huì)使用到。官網(wǎng)也提供了多語言的客戶端供大家操作redis,如下圖所示

自己動(dòng)手寫一個(gè)能操作redis的客戶端

但是,大家有思考過,這些語言操作redis背后的原理么?其實(shí),某些大神會(huì)說

只要按照redis的協(xié)議,發(fā)送指定數(shù)據(jù)給redis,監(jiān)聽返回值即可。


確實(shí),本質(zhì)原理就是如上面那句話所說。博主也是以這種思路,去看了一下JAVA端的開源組件jedis的源碼,然后取其精華,寫了一個(gè)段能操作redis的demo,希望大家能有所收獲。


jedis的github地址為:
https://github.com/xetorthio/jedis


有興趣的童鞋,也可以自行去閱讀。需要說明的是,這畢竟不是源碼分析系列文章,不是帶你去看jedis的源碼。只是借鑒思路,寫一個(gè)能操作redis的程序。

正文

首先,我先說一下操作思路,如下圖所示

自己動(dòng)手寫一個(gè)能操作redis的客戶端

說明一下,上面的第四步,就是我們自己要寫的操作redis的小demo。

1、先寫一個(gè)socket監(jiān)聽6379端口

這個(gè)程序很easy,度娘一下出來一大把

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(6379);
        Socket socket = server.accept();
        byte[] chars = new byte[64];
        socket.getInputStream().read(chars);
        System.out.println(new String(chars));
    }
}

2、采用開源客戶端,操作一次redis

我這里用的是JAVA語言的jedis,大家自己也可以用其他的任意語言組件,目的是為了采集客戶端在操作redis時(shí),發(fā)送出的數(shù)據(jù)

import redis.clients.jedis.Jedis;
public class RedisTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.set("eat", "I want to eat");
    }
}

3、看看socket監(jiān)聽到的數(shù)據(jù)

在這里運(yùn)行一下第二步的代碼,查看第一步的代碼輸出的數(shù)據(jù),如下所示

*3
$3
SET
$3
eat
$13
I want to eat

那么,這組數(shù)據(jù)是什么含義呢?
我們?nèi)ス倬W(wǎng)進(jìn)行查詢。原來,redis的客戶端和服務(wù)端采取了一種RESP協(xié)議。相應(yīng)文檔地址如下
https://redis.io/topics/protocol
RESP設(shè)計(jì)巧妙,它的前景在于下面三個(gè)方面:

  • Simple to implement.

  • Fast to parse.

  • Human readable.

那么+、-、*、:、$這些符號(hào)是什么意思呢?
官網(wǎng)有這么一段話

In RESP, the type of some data depends on the first byte:  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 "*"
 Additionally RESP is able to represent a Null value using a special variation of Bulk Strings or Array as specified later.
 In RESP different parts of the protocol are always terminated with "\r\n" (CRLF).

翻譯過來
(1)簡(jiǎn)單字符串Simple Strings, 以 "+"加號(hào) 開頭
(2)錯(cuò)誤Errors, 以"-"減號(hào) 開頭
(3)整數(shù)型Integer, 以 ":" 冒號(hào)開頭
(4)大字符串類型Bulk Strings, 以 "$"美元符號(hào)開頭,長(zhǎng)度限制512M
(5)組類型Arrays,以 "*"星號(hào)開頭
并且,協(xié)議的每部分都是以 "\r\n" (CRLF) 結(jié)尾的。

OK,那我們剛才的那一串的數(shù)據(jù)的意思就是(沒有看到""\r\n",是因?yàn)橐呀?jīng)轉(zhuǎn)義了,所以無法看到):

*3   數(shù)組包含3個(gè)元素,分別是SET、eat、I want to eat
$3   是一個(gè)字符串,且字符串長(zhǎng)度為3
SET  字符串的內(nèi)容
$3   是一個(gè)字符串,且字符串長(zhǎng)度為3
eat  字符串的內(nèi)容
$13  是一個(gè)字符串,且字符串長(zhǎng)度為13
I want to eat 字符串的內(nèi)容

提問,如果是get命令,那么傳輸?shù)腞ESP的內(nèi)容長(zhǎng)什么樣?
比如有一個(gè)命令get eat,那么此時(shí)的內(nèi)容如下所示

*2
$3
GET
$3
eat

沒有\(zhòng)r\n是因?yàn)橐呀?jīng)轉(zhuǎn)義了,所以沒看到。其他的命令,可以自行測(cè)試。

4、嘗試構(gòu)造一樣的數(shù)據(jù)操作redis

OK,經(jīng)過上面的鋪墊。我們?nèi)绻獙?duì)redis做一個(gè)set操作,則構(gòu)造set命令的RESP協(xié)議內(nèi)容,并且利用socket編程,將這串內(nèi)容發(fā)送給redis即可。這里用java的socket編程實(shí)現(xiàn),用其他語言也是一樣的。
我們有一個(gè)類 RedisClient.java
代碼如下

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class RedisClient {
    private Socket socket;                                     
    private OutputStream outputStream;
    private InputStream inputStream;
    public RedisClient(String host, int port){
        try {
            this.socket = new Socket(host,port);
            this.outputStream = this.socket.getOutputStream();
            this.inputStream = this.socket.getInputStream();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public String set(final String key, String value) {
        StringBuilder sb = new StringBuilder();
        //雖然輸出的時(shí)候,會(huì)被轉(zhuǎn)義,然而我們傳送的時(shí)候還是要帶上\r\n
        sb.append("*3").append("\r\n");
        sb.append("$3").append("\r\n");
        sb.append("SET").append("\r\n");
        sb.append("$").append(key.length()).append("\r\n");
        sb.append(key).append("\r\n");
        sb.append("$").append(value.length()).append("\r\n");
        sb.append(value).append("\r\n");
        byte[] bytes= new byte[1024];
        try {
            outputStream.write(sb.toString().getBytes());
            inputStream.read(bytes);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return new String(bytes);
    }
    public static void main(String[] args) {
        RedisClient redisClient = new RedisClient("127.0.0.1", 6379);
        String result = redisClient.set("eat", "please eat");
        System.out.println(result);     
    }
}

上面的public String set(final String key, String value)方法中,顯示了,我們假如需要對(duì)redis進(jìn)行set操作,需要傳輸?shù)腞ESP協(xié)議的內(nèi)容。記住,一定要帶\r\n字符作為結(jié)尾
OK,運(yùn)行上述代碼,你會(huì)發(fā)現(xiàn)你可以往redis中set數(shù)據(jù)了,并且控制臺(tái)輸出如下

+OK

提問,你自己會(huì)封裝get命令么?

總結(jié)

本文以一種循序漸進(jìn)的方式帶領(lǐng)大家寫了一個(gè)能操作redis的demo,希望大家有所收獲。

分享文章:自己動(dòng)手寫一個(gè)能操作redis的客戶端-創(chuàng)新互聯(lián)
文章鏈接:http://muchs.cn/article0/dphgoo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google做網(wǎng)站、ChatGPT網(wǎng)站制作、網(wǎng)站內(nèi)鏈企業(yè)網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)