原文鏈接: https://mp.weixin.qq.com/s/IBynkex-FHhvJ3tmizvJhA
成都創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、三門網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5網(wǎng)站設(shè)計、成都做商城網(wǎng)站、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為三門等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
redis大家在項目中經(jīng)常會使用到。官網(wǎng)也提供了多語言的客戶端供大家操作redis,如下圖所示
但是,大家有思考過,這些語言操作redis背后的原理么?其實,某些大神會說
只要按照redis的協(xié)議,發(fā)送指定數(shù)據(jù)給redis,監(jiān)聽返回值即可。
確實,本質(zhì)原理就是如上面那句話所說。博主也是以這種思路,去看了一下JAVA端的開源組件jedis的源碼,然后取其精華,寫了一個段能操作redis的demo,希望大家能有所收獲。
jedis的github地址為:
https://github.com/xetorthio/jedis
有興趣的童鞋,也可以自行去閱讀。需要說明的是,這畢竟不是源碼分析系列文章,不是帶你去看jedis的源碼。只是借鑒思路,寫一個能操作redis的程序。
首先,我先說一下操作思路,如下圖所示
說明一下,上面的第四步,就是我們自己要寫的操作redis的小demo。
這個程序很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)); } }
我這里用的是JAVA語言的jedis,大家自己也可以用其他的任意語言組件,目的是為了采集客戶端在操作redis時,發(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"); } }
在這里運(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è)計巧妙,它的前景在于下面三個方面:
Simple to implement.
Fast to parse.
Human readable.
那么+、-、*、:、$這些符號是什么意思呢?
官網(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)簡單字符串Simple Strings, 以 "+"加號 開頭
(2)錯誤Errors, 以"-"減號 開頭
(3)整數(shù)型Integer, 以 ":" 冒號開頭
(4)大字符串類型Bulk Strings, 以 "$"美元符號開頭,長度限制512M
(5)組類型Arrays,以 "*"星號開頭
并且,協(xié)議的每部分都是以 "\r\n" (CRLF) 結(jié)尾的。
OK,那我們剛才的那一串的數(shù)據(jù)的意思就是(沒有看到""\r\n",是因為已經(jīng)轉(zhuǎn)義了,所以無法看到):
*3 數(shù)組包含3個元素,分別是SET、eat、I want to eat $3 是一個字符串,且字符串長度為3 SET 字符串的內(nèi)容 $3 是一個字符串,且字符串長度為3 eat 字符串的內(nèi)容 $13 是一個字符串,且字符串長度為13 I want to eat 字符串的內(nèi)容
提問,如果是get命令,那么傳輸?shù)腞ESP的內(nèi)容長什么樣?
比如有一個命令get eat,那么此時的內(nèi)容如下所示
*2 $3 GET $3 eat
沒有\(zhòng)r\n是因為已經(jīng)轉(zhuǎn)義了,所以沒看到。其他的命令,可以自行測試。
OK,經(jīng)過上面的鋪墊。我們?nèi)绻獙edis做一個set操作,則構(gòu)造set命令的RESP協(xié)議內(nèi)容,并且利用socket編程,將這串內(nèi)容發(fā)送給redis即可。這里用java的socket編程實現(xiàn),用其他語言也是一樣的。
我們有一個類 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(); //雖然輸出的時候,會被轉(zhuǎn)義,然而我們傳送的時候還是要帶上\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)方法中,顯示了,我們假如需要對redis進(jìn)行set操作,需要傳輸?shù)腞ESP協(xié)議的內(nèi)容。記住,一定要帶\r\n字符作為結(jié)尾
OK,運(yùn)行上述代碼,你會發(fā)現(xiàn)你可以往redis中set數(shù)據(jù)了,并且控制臺輸出如下
+OK
提問,你自己會封裝get命令么?
本文以一種循序漸進(jìn)的方式帶領(lǐng)大家寫了一個能操作redis的demo,希望大家有所收獲。
當(dāng)前文章:自己動手寫一個能操作redis的客戶端
文章位置:http://www.rwnh.cn/article2/gcgpic.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、Google、網(wǎng)站建設(shè)、自適應(yīng)網(wǎng)站、定制開發(fā)、面包屑導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)