這是 系列的第一篇文章, 我之前看教學的時候,很多都是從 IO、buffer、path、event、fs、process、node 事件迴圈機制開始說起的. 這些確實是 node 開發主要依賴的開發依賴. 但是我比較著急, 從瞭解到 node,就是說 node 可以幹後端的話,但是這些課程前半截都在說它擁有的能力,就是最後才到如何和使用者端通訊的模組介紹.
我很難受,所以在我自己寫總結的時候,一定要寫先伺服器端和使用者端通訊的模組才舒服.即便過程中涉及到了 event 模組、fs 模組的知識點,可以暫時擱置,只從整體來理解net
模組如何實現通訊的.
想要學明白通訊模組,就不得不瞭解網路通訊模型,想要記住網路通訊模型,就不得不實際操作來輔助記憶. 這個是面試的重點. 這一塊內容很多,想要跟深入的瞭解,還說需要體系的學習的. 這裡只是簡單提提.
寄出這張老圖:
對於我們前端而言, 需要記住 TCP/IP 協定簇的體系結果既可.
應用層: http(80 埠)、FTP(21)、SMTP(傳送郵件)、POP(接收郵件)、DNS
傳輸層: TCP/ UDP
網際層: IP,ICMP(是 IP 層的附屬協定)
資料鏈路層: PPP, SLIP
物理層: 網有雙絞線、同軸電纜、光纖等傳輸方式, 遵循 ISO2110 規範
從ICMP
這種依附於 IP 協定的協定可以知道,對於網路協定的分層不用過於較勁. ICMP
明明需要 IP 協定為基礎,但是它也被規劃為網路層. 我們對於 OSI 模型的正確的認識,我認為應該是用 OSI 模型來進行問題的分析比用來對於協定進行所謂的分層更加來得有意義.
TCP/IP 協定簇 並不是只是指 TCP 和 IP 協定,只是因為這兩個協定過於出圈,所以就用 TCP/IP 來統稱網際網路相關聯的協定集合起來. 還有另外一種說法是,在使用 TCP/IP 協定過程中使用到的協定族的統稱.
而使用者端和伺服器端的傳輸流如下
如果角色變成傳送者
和接受者
的時候,傳輸流如下圖:
可以看出來傳輸的過程中,從傳送端開始,沒經過一層協定都會加上所需要的首部資訊.層層把關,層層加碼. 然後到了接收端的時候, 就反而行之, 每經過一層都剝去對應的首部. 只等到最後拿到的 HTTP 資料.
上面圖片出自《圖解 HTTP》
上面就是大體的網路協定模型.
疑惑: 為什麼書上和很多地方在把 OSI 體系結果中合併成 TCP/IP 五層協定之後,網路層的名稱會變成網際層呢?
第一次握手: 使用者端向伺服器端傳送 SYN 標誌位(序號是 J), 並進入 SYN_SENT 狀態(等待伺服器端確認狀態)
第二次握手: 伺服器端收到來自使用者端的 SYN J, 伺服器端會確認該封包已收到並行送 ACK 標誌位(序號是 J + 1)和 SYN 標誌位(序號是 K), 隨後進入 SYN_REVD 狀態(請求接受並等待使用者端確認狀態)
第三次握手: 使用者端進入連線建立狀態後,向伺服器端傳送 ACK 標誌位(K+ 1) , 確認使用者端已收到建立連線,伺服器收到 ACK 標誌後,伺服器端進入連線已建立狀態.
J 和 K 都是為了確立是誰在請求. SYN 和 ACK 的結構沒有什麼不同,只是傳送的物件不一樣.
net模組
就是對於上面 TCP 連線的具體實現.
首先, 學習 API 依舊推薦直接進入官方檔案. 其中中文檔案內容不會是最新版本的
在學習的時候,能夠有時間看英文檔案就儘量看英文檔案. 對於這一點我堅持了半年. 從一開始看不下去,直到現在能夠可以忍住不舒適感看下去. 半年時間進步就很明顯了. 而且這種不舒適感是一件好事,說明這個不是你的舒適區,畢竟勇於跨過自己的舒適區才是進步的源泉
接下來,進行正題.既然要學習通訊,那麼我們就需要兩個物件來模擬使用者端和伺服器端.分別建立client.js
和service.js
兩個檔案. 通過命令列建立:
touch client.js && touch service.js
引入net
模組,並讓伺服器進入LISTENT
狀態, 以及設定埠號和 HOST 地址(手動略過 DNS 解析過程), 等待使用者端的召喚
const net = require("net"); const post = 3306; const host = "127.0.0.1"; const server = net.createServer(); server.listen(post, host);
此時伺服器對應了 TCP 連線中伺服器LISTEN
狀態.
隨後監聽一些必要的事件,也就是 server 提供的勾點. (屬於 event 相關知識)
server.on("listening", () => { console.log("伺服器已經可以連線啦"); }); server.on("connection", (socket) => { console.log("有使用者端來訪咯"); }); server.on("close", () => { console.log("伺服器關閉了"); }); server.on("error", (error) => { console.log("伺服器出錯啦: ", error); // error 有錯誤的資訊 });
上面這一串程式碼涉及到了,
listening
: 監聽埠後出發的事件connection
: 有使用者端來訪的時候觸發事件close
: 伺服器關閉觸發error
: 伺服器出錯觸發對於close
我們需要注意的是,後臺大哥一般是直接
ps kill -9 pid
通過殺死執行緒的方式來進行的
在connection
狗子中, 形參是 socket 命名. 它的中文翻譯為巢狀字, 被 node 封裝成了 stream(流).在可以粗淺的理解為就是使用者端傳送過來的資料. 這是這個資料自身是有方法的. 我在connection
中對socket
來進行處理
server.on("connection", (socket) => { console.log("有使用者端來訪咯"); socket.on("data", (data) => { console.log(data); // 使用者端傳送過來的資料 }); });
stream 以後的文章會進行介紹.
伺服器端既然能夠接受使用者端發過來的資料,自然也能夠給使用者端回覆. 在socket.on
中寫入(當然也可以寫在外面):
socket.write("我已經收到你的伺服器了哦,使用者端");
此時如果使用者端已經完成了資料的接受,然後關閉了連線.我們可以也可以通過socket.on('close‘)
勾點監聽到:
socket.on("close", () => { console.log("使用者端把另外一頭的流給關了"); });
對於socket
事件的總結放入client.js
中.
此時service.js
的所有內容如下:
const net = require("net"); const post = 3306; const host = "127.0.0.1"; const server = net.createServer(); server.listen(post, host); server.on("listening", () => { console.log("伺服器已經可以連線啦"); }); server.on("connection", (socket) => { console.log("有使用者端來訪咯"); socket.on("data", (data) => { console.log(data); // 使用者端傳送過來的資料 socket.write("我已經收到你的伺服器了哦,使用者端"); }); socket.on("close", () => { console.log("使用者端把另外一頭的流給關了"); server.close(); // 使用者端已經不要資料了,那麼我們就把伺服器給關閉了吧 }); }); server.on("close", () => { console.log("伺服器關閉了"); }); server.on("error", (error) => { console.log("伺服器出錯啦: ", error); // error 有錯誤的資訊 });
使用者端的就簡單很多.
const net = require("net"); const post = 3306; const host = "127.0.0.1"; const socket = net.connect(post, host); socket.on("connect", () => { console.log("已經連線到伺服器了哦"); }); socket.write("伺服器, 我來了"); socket.on("data", (data) => { console.log(data.toString()); socket.end(); }); socket.on("close", () => { console.log("連線已關閉了"); });
對於socket
的事件的總結
connect
: 成功和伺服器連線觸發data
: 接受到伺服器發過來的引數end
: 資料接收完畢之後可以觸發close
: socket 關閉觸發service.js
和client.js
框架已經寫完, 那些先後在開啟兩個終端執行他們:
node service.js node client.js
自行檢視列印的結果.
整個 TCP 連線的框架大體就已經完成了. 當然實際的生產遠遠不止這些. 還要處理粘包、拆包/封包, 心跳包等等.
本文轉載自:https://juejin.cn/post/7084618854801866765
作者:我是小橘子哦
更多node相關知識,請存取:!
以上就是深入淺析Nodejs中的net模組的詳細內容,更多請關注TW511.COM其它相關文章!