redis的ping pong
登錄redis cli客戶端后, 輸入ping, 服務器會返回pong, 來表示連接狀況是完好的, 也表示了服務器大體上是正常運轉的.
其中的第一行是我用docker 啟動的客戶端, 大家如果不是docker的話, 自己正常啟動redis -cli就行..
ping之后就會收到pong
使用Java socket 來實現 Redis 的ping pong
public?static?void?main(String[]?args)?throws?Exception?{ ????????//?socket ????????Socket?socket?=?new?Socket("140.143.135.210",?6379); ? ????????//?oi流 ????????OutputStream?os?=?socket.getOutputStream(); ????????InputStream?is?=?socket.getInputStream(); ? ????????//?向redis服務器寫 ????????os.write("PINGrn".getBytes()); ? ????????//從redis服務器讀,到bytes中 ????????byte[]?bytes?=?new?byte[1024]; ????????int?len?=?is.read(bytes); ? ????????//?to?string?輸出一下 ????????System.out.println(new?String(bytes,0,len)); ????}
返回的結果如下:
為什么會有一個 ‘+’符號 呢?? redis -cli里是沒有這個加號的呀???
這個和通信協議有關, 一會兒再介紹具體的含義. 不過redis -cli只是把這個’+’符號吞掉處理了, 沒顯示出來罷了。
public?static?void?main(String[]?args)?throws?Exception?{ ????????//?socket ????????Socket?socket?=?new?Socket("140.143.135.210",?6379); ? ????????//?oi流 ????????OutputStream?os?=?socket.getOutputStream(); ????????InputStream?is?=?socket.getInputStream(); ? ????????//?向redis服務器寫 ????????os.write("PINGrn".getBytes()); ? ????????//從redis服務器讀,到bytes中 ????????byte[]?bytes?=?new?byte[1024]; ????????if(is.read()=='+'){ ????????????//?to?string?輸出一下 ????????????int?len?=?is.read(bytes); ????????????System.out.println(new?String(bytes,0,len)); ????????} ????????//?else?if?$ ????????//?else?if?* ????????//?else ????}
?這樣就跟redis -cli里的一樣啦.就只是pong了
實現SET 和 GET
?set:
public?static?void?main(String[]?args)?throws?Exception?{ ????????//?socket ????????Socket?socket?=?new?Socket("140.143.135.210",?6379); ? ????????//?oi流 ????????OutputStream?os?=?socket.getOutputStream(); ????????InputStream?is?=?socket.getInputStream(); ? ????????//?向redis服務器寫 ????????os.write("set?hello?world123rn".getBytes()); ? ????????//從redis服務器讀,到bytes中 ????????byte[]?bytes?=?new?byte[1024]; ????????int?len?=?is.read(bytes); ? ????????//?to?string?輸出一下 ????????System.out.println(new?String(bytes,0,len)); ????}
get:
public?static?void?main(String[]?args)?throws?Exception?{ ????????//?socket ????????Socket?socket?=?new?Socket("140.143.135.310",?6379); ? ????????//?oi流 ????????OutputStream?os?=?socket.getOutputStream(); ????????InputStream?is?=?socket.getInputStream(); ? ????????//?向redis服務器寫 ????????os.write("get?hellorn".getBytes()); ? ????????//從redis服務器讀,到bytes中 ????????byte[]?bytes?=?new?byte[1024]; ????????int?len?=?is.read(bytes); ? ????????//?to?string?輸出一下 ????????System.out.println(new?String(bytes,0,len)); ????}
解釋上面例子中的+和$符號
加號’+’ 是來表示狀態回復的, 在redis服務端向客戶端返回狀態信息時, 就會先發送一個`+`符號來開頭.
接下來是相應的狀態信息, 例如’OK’什么的.
最后, 要以’rn’ 來結尾… 咱們看一下代碼就明白了
public?static?void?main(String[]?args)?throws?Exception?{ ????????//?socket ????????Socket?socket?=?new?Socket("140.143.135.210",?6379); ? ????????//?oi流 ????????OutputStream?os?=?socket.getOutputStream(); ????????InputStream?is?=?socket.getInputStream(); ? ????????//?向redis服務器寫 ????????os.write("set?hello?world123rn".getBytes()); ? ????????//從redis服務器讀,到bytes中 ????????byte[]?bytes?=?new?byte[1024]; ????????if?(is.read()?==?'+')?{ ????????????System.out.println("這是一個狀態回復哦!?怎么知道的呢??`+`?號就表示?'狀態回復'?了"); ????????????int?len?=?is.read(bytes); ????????????System.out.println("回復的狀態是:?"?+?new?String(bytes,?0,?len)); ????????} ? ????????//?大家想不想看看bytes里面到底有幾個字符嗎? ????????System.out.println(Arrays.toString(bytes)); ????????//?輸出的是?[79,?75,?13,?10,?0,?0,?0,?0,?0,....] ????????//?其中?79?75?是?`OK` ????????//?其中?13?10?是?`rn` ????????//?后面的一串0?是?表示沒有后續內容,?已經讀完. ????}
?$ 表示批量讀取, 一般格式是: $, 數字來表示正文的內容的字節數?
抓包后是這樣的, 客戶端向服務端發送了”get hello”, 服務端向客戶端發送了藍色的這兩行.
public?static?void?main(String[]?args)?throws?Exception?{ ????????//?socket ????????Socket?socket?=?new?Socket("140.143.135.210",?6379); ? ????????//?oi流 ????????OutputStream?os?=?socket.getOutputStream(); ????????//?為了解析'rn'方便,?我就用改為字符流了 ????????BufferedReader?br?=?new?BufferedReader(new?InputStreamReader(socket.getInputStream())); ? ????????//?向redis服務器寫 ????????os.write("get?hellorn".getBytes()); ? ????????//?緩沖數組 ????????char[]?chars?=?new?char[1024]; ? ????????//從redis服務器讀,到bytes中 ????????if?(br.read()?==?'$')?{ ????????????System.out.println("這是一個批量回復哦!?怎么知道的呢??`$`?號就表示?'批量回復'?了"); ????????????System.out.println("$?后面會跟一個數字,?來表示正文內容的大小"); ????????????//?readLine直接能判斷'r'?'n' ????????????int?len?=?Integer.parseInt(br.readLine()); ????????????System.out.println("$后面跟著的數字是:?"?+?len?+?",?表示正文是"?+?len?+?"個字節,?接下來只要讀取"?+?len?+?"個字節就好了"); ? ????????????//?接下來只讀取len個字符就ok了??(其實單位應該是字節,?但是我中途為了readLine省事,?改用了字符流,?個數是不變的) ????????????br.read(chars,?0,?len); ????????????System.out.println("get到的結果是:?"?+?new?String(chars,?0,?len)?+?",?數一數真的是"?+?len?+?"個字符"); ????????} ????}
Redis通信協議就只是這樣?
no!!!剛才客戶端向服務端發送的 “get hello” , 這種只是”內聯命令”, 而不是Redis真正的通信協議.
問: 什么意思呢? 答:? 就是說你可以像之前那樣給服務端發, 服務器端接受到后, 會遍歷一遍你發送的內容, 最后根據空格來分析你所發的內容的含義.
問: 這樣有什么不好的嗎?? 答: 如果這樣的話, 你就把解析的工作交給了服務器來做, 會加大服務器的工作量.
問: 那怎么樣才是符合規范的呢? 符合協議的話真的會提高服務器的效率??答: 首先看一下符合協議的客戶端和服務端之間的交互把.如下例子:
例: set java python ,抓到包之后是這樣的:
紅色是客戶端發送的內容,?藍色是服務器端返回的內容.
咱們一起解析一下:
*3表示 , 客戶端即將發送3段內容
哪三段呢? 第一段: ‘$3 SET’? 第二段: ‘$4 java’? ?第三段: ‘$6 python’
更嚴格地說: 第一段: ‘$3rnSETrn’? 第二段:’$4rnjavarn’? 第三段:’$6rnpythonrn’
$符號的意思在上一小節就已經提到過了, 表示下文的內容的長度, 方便服務器進行讀取.
例如: $6就已經把python的長度給匯報出來了, 服務器只需要截取區間[index, index+6]就好了, 不需要去找空格在什么地方(找空格的時間復雜度是O(n), 而$6這種寫法是O(1) )
?Jedis
其實Jedis做的工作大體就是把SET key value 這樣的格式轉化為下面這種格式, 然后發到Redis服務端:
*3rn $3rn SETrn $3rn keyrn $5rn valuern
更多redis知識請關注redis入門教程欄目。