【Redis学习】redis通讯协议
服務是一個較抽象的概念,意在幫助使用者達到某種需求。那么對于網絡服務來說,通常我們可以將其定義為一個運行在操作系統(tǒng)上的程序,使用者通過網絡與其進行交互并得到想要的信息。
客戶端和服務器通過TCP連接來進行數(shù)據(jù)交互,所以它和其它網絡服務一樣有一個協(xié)議。redis服務器接受命令以及命令的參數(shù)。服務器會在接到命令之后對命令進行處理,并將命令的回復傳送到客戶端。具體在網絡層上就是:Redis在TCP端口6379上監(jiān)聽到來的連接,客戶端連接到來時,Redis服務器為此創(chuàng)建一個TCP連接。在客戶端與服務器端之間傳輸?shù)拿總€Redis命令或者數(shù)據(jù)都以\r\n結尾。
redis的通訊協(xié)議包括:消息頭標識和消息行,消息行里可能還有一個數(shù)據(jù)塊大小的描述。redis是以行來劃分的,每行以\r\n結束,且每一行都有一個消息頭。
消息體一共分為5種類型:
(1)[+]表示一個正確的狀態(tài)信息,具體信息是:當前行+后面的字符
(2)[-]表示一個錯誤信息,具體信息是:當前行-后面的字符
(3)[]表示消息體總共有多少行,不包括當前行,后面是具體的行數(shù)
(4)[]表示下一行數(shù)據(jù)長度,不包括換行符\r\n的長度,]表示下一行數(shù)據(jù)長度,不包括換行符\r\n的長度,后面則是對應長度的數(shù)據(jù)
(5)[:]表示返回一個數(shù)值,:后面是相應的數(shù)字字符
redis命令會返回多種不同類型的回復,通過檢查服務器發(fā)回數(shù)據(jù)的第一個字節(jié),可以確定這個回復是什么類型:
(1)狀態(tài)回復的第一個字節(jié)是[+]
(2)錯誤回復的第一個字節(jié)是[-]
(3)整數(shù)回復的第一個字節(jié)是[:]
(4)批量回復的第一個字節(jié)是[$]
(5)多條批量回復的第一個字節(jié)是[*]
具體指令和返回:
1、SET
client : SET MYTEST HELLO設置MYTEST的值為HELLO。
在redis的通訊協(xié)議上會以空格把命令拆分成三行,得到最終的命令如下:
server :
服務端操作成功:+OK\r\n
如果服務端返回錯誤: -錯誤信息\r\n
2、GET
client : GET MYTEST產生的通訊指令:
*2\r\n $3\r\n GET\r\n $6\r\n MYTESTserver : 如果存在這個key則返回:
$5\r\n HELLO\r\n3、HKEYS
client : HKEYS MYTEST以上命令是獲取對應MYTEST有多少個field成員:
*2\r\n $5\r\n HKEYS\r\n $6\r\n MYTEST\r\nserver :
如果不存在任何字段信息:*0\r\n
如果存在一個AGE字段信息:
4、HMGET
client : HMGET MYTEST AGE以上命令是獲取HENRY的QQ信息。
*3\r\n $5\r\n HMGET\r\n $6\r\n MYTEST\r\n $3\r\n AGE\r\nserver :
如果不存在字段值
*1\r\n $-1\r\n存在字段值
*1\r\n $2\r\n 28\r\n以上主要列舉Redis普遍處理的一些情況,由于指令太多就不一一列舉了,如果有需要自己實現(xiàn)Client的朋友可以到Redis官方看相關命令文檔。redis官方文檔
練習小程序:通過socket和redis server進行通信
import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.Charset; public class SimpleProtocol {public static void main(String[] args) throws Exception{Socket socket = new Socket();socket.setReuseAddress(true);//空閑時發(fā)送數(shù)據(jù)包,確認服務端狀態(tài)socket.setKeepAlive(true);//關閉Nagle算法,盡快發(fā)送socket.setTcpNoDelay(true);socket.setSoLinger(true, 0);//連接serversocket.connect(new InetSocketAddress("localhost", 6379), 3000);//設置讀取時超時時間socket.setSoTimeout(3000);OutputStream os = socket.getOutputStream();/*** SET 命令* 協(xié)議: array 3個元素 SET simpleKey simpleValue*/os.write(getBytes("*3\\r\\n$3\\r\\nSET\\r\\n$9\\r\\nsimpleKey\\r\\n$11\\r\\nsimpleValue\\r\\n"));os.flush();InputStream is = socket.getInputStream();/*** 解析SET命令的返回結果*/String result = analysisResult(is);System.out.println("SET command response : " + result);System.out.println();/*** GET 命令* 協(xié)議: array 2個元素 GET simpleKey*/os.write(getBytes("*2\\r\\n$3\\r\\nGET\\r\\n$9\\r\\nsimpleKey\\r\\n"));os.flush();/*** 解析GET命令返回結果*/String value = analysisResult(is);System.out.println("GET command response : " + value);is.close();os.close();socket.close();}/*** 解析返回結果* @param is* @return* @throws Exception*/private static String analysisResult(InputStream is) throws Exception{/*** 第一個字節(jié)指定返回的數(shù)據(jù)結構類型*/byte type = (byte)is.read();System.out.println("response type is : " + (char)type);if(type == '+'){//Simple String類型return readCRLF(is);}else if(type == '$'){//Bulk String類型int len = readIntCRLF(is);System.out.println("$ value len : " + len);return readFixedLen(is, len);}return null;}/*** 讀取int值,直到遇到CRLF* @param is* @return* @throws Exception*/private static int readIntCRLF(InputStream is) throws Exception{return Integer.parseInt(readCRLF(is));}/*** 讀取字符串,直到遇到CRLF* @param is* @return* @throws Exception*/private static String readCRLF(InputStream is) throws Exception{byte b = (byte)is.read();StringBuilder sb = new StringBuilder();//不是最后一個輸入字節(jié)時while(b != -1){//判斷是否是CR,如果不是加入sb中if(b != '\\r'){sb.append((char)b);}else{//如果是CR,繼續(xù)讀取一個字節(jié),如果不是LF,報錯byte oneMore = (byte)is.read();if(oneMore != '\\n'){throw new RuntimeException("CRLF error!");}else{break;}}b = (byte)is.read();}return sb.toString();}/*** 讀取固定字節(jié)長度的字符串* @param is* @param len* @return* @throws Exception*/private static String readFixedLen(InputStream is, int len) throws Exception{byte[] bytes = new byte[len];for(int i = 0; i < len; i++){bytes[i] = (byte)is.read();}//CRis.read();//LFis.read();return new String(bytes, "UTF-8");}private static byte[] getBytes(String str) throws Exception{return str.getBytes(Charset.forName("UTF-8"));} }運行結果;
response type is : +SET command response : OKresponse type is : $$ value len : 11GET command response : simpleValue 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的【Redis学习】redis通讯协议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web性能压测——webbench
- 下一篇: 【Redis学习】Redis开启多个端口