自己動手寫一個能操作redis的客戶端
作者:孤獨煙 來源:微信訂閱號(程式設計師孤獨煙)
原文連結: https://mp.weixin.qq.com/s/IBynkex-FHhvJ3tmizvJhA
引言
redis大家在專案中經常會使用到。官網也提供了多語言的客戶端供大家操作redis,如下圖所示
但是,大家有思考過,這些語言操作redis背後的原理麼?其實,某些大神會說
只要按照redis的協議,傳送指定資料給redis,監聽返回值即可。
確實,本質原理就是如上面那句話所說。博主也是以這種思路,去看了一下JAVA端的開源元件jedis的原始碼,然後取其精華,寫了一個段能操作redis的demo,希望大家能有所收穫。
jedis的github地址為:
https://github.com/xetorthio/jedis
有興趣的童鞋,也可以自行去閱讀。需要說明的是,這畢竟不是原始碼分析系列文章,不是帶你去看jedis的原始碼。只是借鑑思路,寫一個能操作redis的程式。
正文
首先,我先說一下操作思路,如下圖所示
說明一下,上面的第四步,就是我們自己要寫的操作redis的小demo。
1、先寫一個socket監聽6379埠
這個程式很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時,傳送出的資料
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監聽到的資料
在這裡執行一下第二步的程式碼,檢視第一步的程式碼輸出的資料,如下所示
*3 $3 SET $3 eat $13 I want to eat
那麼,這組資料是什麼含義呢?
我們去官網進行查詢。原來,redis的客戶端和服務端採取了一種RESP協議。相應文件地址如下
https://redis.io/topics/protocol
RESP設計巧妙,它的前景在於下面三個方面:
-
Simple to implement.
-
Fast to parse.
-
Human readable.
那麼+、-、*、:、$這些符號是什麼意思呢?
官網有這麼一段話
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)整數型Integer, 以 ":" 冒號開頭
(4)大字串型別Bulk Strings, 以 "$"美元符號開頭,長度限制512M
(5)組型別Arrays,以 "*"星號開頭
並且,協議的每部分都是以 "\r\n" (CRLF) 結尾的。
OK,那我們剛才的那一串的資料的意思就是(沒有看到""\r\n",是因為已經轉義了,所以無法看到):
*3 陣列包含3個元素,分別是SET、eat、I want to eat $3 是一個字串,且字串長度為3 SET 字串的內容 $3 是一個字串,且字串長度為3 eat 字串的內容 $13 是一個字串,且字串長度為13 I want to eat 字串的內容
提問,如果是get命令,那麼傳輸的RESP的內容長什麼樣?
比如有一個命令get eat,那麼此時的內容如下所示
*2 $3 GET $3 eat
沒有\r\n是因為已經轉義了,所以沒看到。其他的命令,可以自行測試。
4、嘗試構造一樣的資料操作redis
OK,經過上面的鋪墊。我們如果要對redis做一個set操作,則構造set命令的RESP協議內容,並且利用socket程式設計,將這串內容傳送給redis即可。這裡用java的socket程式設計實現,用其他語言也是一樣的。
我們有一個類 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(); //雖然輸出的時候,會被轉義,然而我們傳送的時候還是要帶上\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進行set操作,需要傳輸的RESP協議的內容。記住,一定要帶\r\n字元作為結尾
OK,執行上述程式碼,你會發現你可以往redis中set資料了,並且控制檯輸出如下
+OK
提問,你自己會封裝get命令麼?
總結
本文以一種循序漸進的方式帶領大家寫了一個能操作redis的demo,希望大家有所收穫。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31473948/viewspace-2168868/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 自己動手寫個 Android客戶端Android客戶端
- 盤點一下Redis中常用的Java客戶端,或者我們們手寫一個?RedisJava客戶端
- 學習T-io框架,從寫一個Redis客戶端開始框架Redis客戶端
- 【redis前傳】自己手寫一個LRU策略 | redis淘汰策略Redis
- 寫一個Flutter彩票客戶端--開獎列表Flutter客戶端
- [Redis 客戶端整合] Java 中常用Redis客戶端比較Redis客戶端Java
- 自己動手寫一個持久層框架框架
- redis客戶端管理Redis客戶端
- Redis-客戶端Redis客戶端
- 手寫一個自己的PromisePromise
- Elasticsearch的PHP客戶端操作ElasticsearchPHP客戶端
- OrzClick: 國慶寫個 ClickHouse 客戶端客戶端
- Redis客戶端基本操作以及檢視慢查詢Redis客戶端
- 如何用Java Socket實現一個簡單的Redis客戶端JavaRedis客戶端
- mongodb/redis/neo4j 如何自己打造一個 web 資料庫視覺化客戶端?MongoDBRedisWeb資料庫視覺化客戶端
- redis客戶端實現高可用讀寫分離Redis客戶端
- day03-Redis的客戶端Redis客戶端
- redis:常用客戶端命令(redis-cli)Redis客戶端
- 初探 Redis 客戶端 Lettuce:真香!Redis客戶端
- 4款.NET開源的Redis客戶端驅動庫Redis客戶端
- 如何編寫一個前端框架之七-客戶端路由(譯)前端框架客戶端路由
- Redis的Pub/Sub客戶端實現Redis客戶端
- RMAN之客戶端互動(一)客戶端
- 一個現代化輕量級的跨平臺Redis桌面客戶端Redis客戶端
- grpc套路客戶端編寫RPC客戶端
- 實現一個clickhouse tcp協議客戶端驅動TCP協議客戶端
- Flutter寫的部落格園客戶端Flutter客戶端
- Redis客戶端連線數DevOpsRedis客戶端dev
- Redis客戶端選型再分析Redis客戶端
- Windows下安裝redis客戶端WindowsRedis客戶端
- [Redis 客戶端整合] SpringBoot 整合 LettuceRedis客戶端Spring Boot
- [Redis 客戶端整合] SpringBoot 整合 JedisRedis客戶端Spring Boot
- mysql、redis 客戶端連線池MySqlRedis客戶端
- VNC客戶端是Windows,VNC客戶端是Windows如何進行操作VNC客戶端Windows
- Go 實現簡易的 Redis 客戶端GoRedis客戶端
- [轉載] 使用Redis的Java客戶端JedisRedisJava客戶端
- Neeto-Vue:我為了記筆記,手寫了一個為知筆記客戶端Vue筆記客戶端
- InfluxDB 客戶端基礎操作2UX客戶端