使用Nodejs?實現(xiàn)一個簡單的?Redis客戶端(推薦)
0. 寫在前面
大家如果有去看過nodejs所支持的官方庫的話,應(yīng)該會驚訝于它所提供了非常完善的網(wǎng)絡(luò)庫,不僅是應(yīng)用層,傳輸層,等等基礎(chǔ)的協(xié)議,我們可以按照事件驅(qū)動的邏輯編寫清晰易懂的網(wǎng)絡(luò)應(yīng)用,網(wǎng)絡(luò)服務(wù)。這也是本文為什么選擇Nodejs編寫的原因。
1. 背景映入
大家在使用一些數(shù)據(jù)庫軟件的時候常常會使用遠程連接
mysql -h xxx.xxx.xxx.xx -u xzzz -p
這里也指明了ip地址,但是很明顯這里可不是http協(xié)議在服務(wù),而是更加底層的協(xié)議 - 傳輸層協(xié)議,具體來說是TCP協(xié)議(Transmission Control Protocol)。通信的示意圖如下:

所以很自然的想到,數(shù)據(jù)庫的客戶端一定經(jīng)過如下流程,從而與遠程相連接:
graph TB身份驗證 --> 運輸層連接建立運輸層連接建立 --> 客戶端服務(wù)端輸入輸出綁定_通道客戶端服務(wù)端輸入輸出綁定_通道 --> 連接中斷連接中斷 --> 雙方退出釋放資源
所以我們可以嘗試向服務(wù)端發(fā)送這樣的請求消息,建立與服務(wù)端的連接,發(fā)送一些數(shù)據(jù),接受一些數(shù)據(jù),最后斷開連接。
2. 數(shù)據(jù)庫選擇
這里為了簡單起見,我們考慮不需要身份驗證的redis數(shù)據(jù)庫來作為此次實驗的服務(wù)端。
如果大家是mac,或者linux倒是可以直接安裝,如果是windows的話,推薦使用docker進行安裝,這里給出一行docker命令。
docker run --name redis-server -p 6379:6379 -d redis:latest
3. Nodejs TCP連接
在nodejs中支持TCP連接的是net模塊, 其中使用createConnection(config)或者直接new Socket(config)來初始化一個TCP連接。
上面兩個函數(shù)不論哪一個都會返回socket實例,如果連接正常的話,就可以通過這個socket發(fā)送消息了。


當(dāng)服務(wù)端redis接收到消息之后也會返回相應(yīng)的消息,在本機客戶端通過對數(shù)據(jù)的校驗,檢查后,觸發(fā)相應(yīng)的操作(是拒絕還是接受服務(wù)端的響應(yīng))。
4. 代碼編寫
知道了原理之后,我這里直接把代碼貼出來
- RedisSocket: 繼承自Socket
class RedisSocket extends Socket {
constructor(config: RedisClientConfig) {
super();
this.connect(config.port, config.host);
}
// Set
public set(key: string, value: string | number): Promise<Buffer> {
return new Promise((resolve, reject) => {
this.write(`SET ${key} ${value}\n`);
const fetchAns = (chunk: Buffer) => {
if (chunk.toString().includes("OK")) {
resolve(chunk);
this.off("data", fetchAns);
// 在交付完成之后使用off 把函數(shù)取消綁定
} else {
reject("error! can't set data");
}
}
this.on("data", fetchAns);
})
}
// Get
public get(key: string): Promise<Buffer> {
return new Promise((resolve, reject) => {
try {
this.write(`GET ${key}\n`);
const fetchAns = (chunk: Buffer) => {
resolve(chunk);
this.off("data", fetchAns);
// 在交付完成之后使用off 把函數(shù)取消綁定
}
this.on("data", fetchAns);
} catch(err) {
reject(err);
}
})
}
// 斷開TCP
public close() {
this.end();
}
}
這個類將用來處理建立好后的連接的
- RedisClient
class RedisClient {
private config: RedisClientConfig;
constructor(config: RedisClientConfig) {
this.config = config; // 配置項
}
// 獲取redis實例
getConnection(): Promise<RedisSocket> {
return new Promise((resolve, reject) => {
const socket = new RedisSocket(this.config);
socket.on("connect", () => {
resolve(socket);
});
socket.on("error", (err) => {
reject(err);
});
});
}
}這個類用來建立與服務(wù)端的連接,使用getConnection()方法,將會交付一個redisSocket,使用這個Socket可以直接向server發(fā)送和接受數(shù)據(jù)。
5. 實驗
import { RedisClient, RedisSocket } from "./src/Client";
const Redis = new RedisClient({
host: "localhost",
port: 6379
});
Redis.getConnection().then((socket: RedisSocket) => {
socket.set("Mushroom", "Cookie");
socket.set("Mici", "Icmi").then( () => {
socket.get("Mushroom").then((data: Buffer) => {
console.log(data.toString());
socket.close();
})
});
})
這里使用RedisClient建立與本地redis的連接,隨后通過getConnection()獲取到連接實例,并通過這個連接實例設(shè)置了兩個數(shù)據(jù),以及獲取了一數(shù)據(jù)并打印了出來。
> pnpm dev > $6 // 這里的$6你也許會感到奇怪,不過我們很快就會知道這是什么 > Cookie
6. wireshark 抓包分析

這一次請求就是一整個完整的TCP流程,
在這其中TCP保證數(shù)據(jù)的可靠傳輸,而RESP(REdis Serialization Protocol)把數(shù)據(jù)封裝成一個fragment段,發(fā)送到下面的TCP
服務(wù)端相應(yīng)的時候也是如此,會把數(shù)據(jù)封裝起來發(fā)送到TCP中轉(zhuǎn)發(fā)出去。
看看發(fā)送方的RESP

看看響應(yīng)的RESP


所以知道了嗎?沒錯,6其實就是長度那一部分強行轉(zhuǎn)化為字符串的結(jié)果,所以在現(xiàn)在很多流行的redis客戶端中如ioredis都對RESP報文做了非常完備的解析,這使得開發(fā)者能夠非常絲滑的與redis服務(wù)端交互。(感謝這些開發(fā)者做的一切!)
7. 雜與代碼
到此這篇關(guān)于用Nodejs 實現(xiàn)一個簡單的 Redis客戶端的文章就介紹到這了,更多相關(guān)Nodejs實現(xiàn)Redis客戶端內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Node.js利用node-git-server快速搭建git服務(wù)器
本篇文章主要介紹了詳解Node.js利用node-git-server快速搭建git服務(wù)器,非常具有實用價值,需要的朋友可以參考下2017-09-09
Node.js+Express+Vue+MySQL+axios的項目搭建全過程
這篇文章主要介紹了Node.js+Express+Vue+MySQL+axios的項目搭建全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
Node.js+Express.js+TS實現(xiàn)簡單圖床腳本
在這篇博客文章中,我將介紹如何使用 TypeScript 和 Express 框架來編寫一個簡單的圖床腳本,可以將本地圖片上傳到服務(wù)器,并返回圖片的 URL,這樣,你就可以在 Markdown 文檔中方便地引用圖片,而不用擔(dān)心圖片的存儲和管理問題2023-10-10
nodejs使用socket5進行代理請求的實現(xiàn)
這篇文章主要介紹了nodejs使用socket5進行代理請求的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
node.js基于socket.io快速實現(xiàn)一個實時通訊應(yīng)用
這篇文章主要介紹了node.js基于socket.io快速實現(xiàn)一個實時通訊應(yīng)用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04

