對 Websocket 完全不懂,但又想搞個聊天室,行嗎?
本文轉(zhuǎn)載自微信公眾號「勾勾的前端世界」,作者xilingls。轉(zhuǎn)載本文請聯(lián)系勾勾的前端世界公眾號。
回憶以下上一篇內(nèi)容:《有了 HTTP 協(xié)議,為什么還需要 Websocket?》,了解一下 Websocket 的特點和通信原理,我們接著來看 Websocket 服務(wù)端與客戶端實現(xiàn)。
Websocket 服務(wù)端與客戶端實現(xiàn)
經(jīng)過前面對通信過程的梳理,我們將 WebSocket 通信的基本機(jī)制已經(jīng)說的差不多了,為了方便你快速進(jìn)入實戰(zhàn)階段,我們暫時放棄純手寫實現(xiàn),直接選擇使用老牌的 WebSocket 庫: WebSocket-Nodehttps://github.com/theturtle32/WebSocket-Node
簡單介紹一下 WebSocket-Node,它有多老牌呢?
NPM 的包名字就是直接使用的 “WebSocket”。曾經(jīng),我們西嶺老濕看到之后就給出了兩個字的評價:“猖狂”。
這個庫完全使用 JavaScript 實現(xiàn),包含了客戶端及服務(wù)端的實例。其中,客戶端包含了 Node 和 瀏覽器 兩個運行環(huán)境的代碼,除了支持我們前面提到的 Websocket 協(xié)議的 13 版本,它同時還支持 Websocket 協(xié)議 8 這個老版本,實屬優(yōu)秀。
接下來,我們就來看看,如何借助 Websocket-Node 實現(xiàn)一個 Websocket 服務(wù)。
服務(wù)端
安裝 npm install websocket 后,創(chuàng)建服務(wù)器運行文件 ws-server.js ,代碼如下,請認(rèn)真閱讀代碼及注釋:
- // === 作為帥哥,一定要加注釋 ===
 - var Websocket = require('websocket').server
 - var http = require('http')
 - // 創(chuàng)建 HTTP 服務(wù),作為第一次握手鏈接使用
 - var httpServer = http.createServer().listen(8080,function(){
 - console.log('http://127.0.0.1:8080')
 - })
 - // 創(chuàng)建 websocket 服務(wù)實力
 - var wsServer = new Websocket({
 - // 配置依賴的握手 http 服務(wù)器
 - httpServer:httpServer,
 - autoAcceptConnections:false
 - })
 - // 保存鏈接池
 - var conArr = []
 - // 監(jiān)聽 ws 請求事件
 - wsServer.on('request',function(request){
 - // 獲取鏈接示例
 - var connection = request.accept()
 - // 保存連接池
 - conArr.push(connection)
 - // 監(jiān)聽消息事件
 - connection.on('message',function(msg){
 - console.log(msg)
 - // 循環(huán)連接池,推送廣播消息至客戶端
 - for(let i = 0;i<conArr.length;i++){
 - conArr[i].send(msg.utf8Data)
 - }
 - })
 - })
 - // 據(jù)說,長得好看的都會看注釋
 
過多的描述,就不寫了,據(jù)說,長得好看的都會看代碼注釋(●'?'●)
運行代碼文件后,不出意外的情況下,命令行進(jìn)程會被占用,監(jiān)聽端口也會被占用,證明服務(wù)端運行成功。如果兩個都沒被占用,想啥呢?失敗了呀寶子……
如果服務(wù)器啟動成功,我怎么用客戶端建立鏈接查看呢?有一款 Websocket 客戶端工具叫 WebsocketMan,如果感興趣,你可以下載來試試。
但是像我這樣的帥哥,一般都是自己寫客戶端:)
客戶端
Websocket 的客戶端并沒有什么技術(shù)難點,就是瀏覽器 API 調(diào)用。只要你把通信機(jī)制夠清楚,這玩意就沒有不會,因為非常簡單,我們直接選擇純手寫就可以了,如果你想使用 Websocket-Node 客戶端,確實還會更簡單。
當(dāng)然,在寫之前,還是要去看看手冊的,要不然你怎么知道有哪些 API 呢?
來,手冊地址給你:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
你先看著,我就不客氣,直接開干……
- <body>
 - <div id="msg"></div>
 - <input type="text" id="text">
 - <input type="button" value="發(fā)送" onclick="send()">
 - <script>
 - //調(diào)用websocket對象建立連接:
 - //參數(shù):ws/wss(加密)://ip:port (字符串)
 - var websocket = new WebSocket('ws://127.0.0.1:8080')
 - // console.log(websocket.readyState) // 0
 - // readyState
 - // 0 鏈接還沒有建立(正在建立鏈接)
 - // 1 鏈接建立成
 - // 2 鏈接正在關(guān)閉
 - // 3 鏈接已經(jīng)關(guān)閉
 - // 監(jiān)聽鏈接開啟事件
 - websocket.onopen = function () {
 - console.log(websocket.readyState)
 - }
 - // 綁定按鈕點擊事件
 - function send() {
 - var text = document.getElementById('text').value
 - // ws 消息發(fā)送
 - websocket.send(text)
 - }
 - // 監(jiān)聽服務(wù)端消息推送事件
 - websocket.onmessage = function (back) {
 - console.log(back.data)
 - }
 - // 監(jiān)聽連接錯誤信息
 - // websocket.onerror = function (evt, e) {
 - // console.log('Error occured: ' + evt.data);
 - // };
 - //監(jiān)聽連接關(guān)閉
 - // websocket.onclose = function (evt) {
 - // console.log("Disconnected");
 - // };
 - </script>
 - </body>
 
過多的描述,就不寫了,據(jù)說,長得好看的都會看代碼注釋(●'?'●)
至此,一個完整的 websocket 通信已經(jīng)建立完成并能夠進(jìn)行雙向通信了。
Websocket-Node 確實很好用,但是功能也確實比較單一了,需要你對 WebSocket 機(jī)制有一定的理解之后,才能實現(xiàn)相應(yīng)的能力。如果,我對 websocket 完全不懂,但又想搞個聊天室,能不能行?
指!定!能!行!
Socket.IO
一個目前最為強(qiáng)大且好用的,基本屏蔽了 websocket 概念的 websocket 庫。你幾乎不用掌握 websocket 相關(guān)的知識,只需要按照 Socket.IO 中提供的 API 就能夠很好的實現(xiàn)一個 websocket 通信。
注意:程序員要“除機(jī)心”。
- 在不了解 Websocket 時,學(xué)習(xí) Websocket 中,強(qiáng)烈不建議使用。
 - 在生產(chǎn)環(huán)境下,強(qiáng)烈建議使用。
 
服務(wù)端
- const { createServer } = require("http");
 - const { Server } = require("socket.io");
 - const httpServer = createServer();
 - const io = new Server(httpServer, {
 - cors: {
 - origin: "*",
 - methods: ["GET", "POST"]
 - }
 - });
 - io.on("connection", (socket) => {
 - socket.on('sendMsg',(data)=>{
 - io.emit('pushMsg',data)
 - })
 - });
 - httpServer.listen(3000, function () {
 - console.log('http://127.0.0.1:3000')
 - });
 
客戶端
- <!DOCTYPE html>
 - <html lang="en">
 - <head>
 - <meta charset="UTF-8">
 - <meta http-equiv="X-UA-Compatible" content="IE=edge">
 - <meta name="viewport" content="width=device-width, initial-scale=1.0">
 - <title>Document</title>
 - <script src="https://cdn.socket.io/4.2.0/socket.io.min.js"
 - integrity="sha384-PiBR5S00EtOj2Lto9Uu81cmoyZqR57XcOna1oAuVuIEjzj0wpqDVfD0JA9eXlRsj"
 - crossorigin="anonymous"></script>
 - </head>
 - <body>
 - <input type="text" id="text">
 - <input type="button" value="發(fā)送" onclick="send()">
 - <script>
 - var socket = io.connect('http://127.0.0.1:3000')
 - function send() {
 - var text = document.getElementById('text').value
 - socket.emit('sendMsg', text)
 - }
 - socket.on('pushMsg', (data) => {
 - console.log(data)
 - })
 - </script>
 - </body>
 - </html>
 
沒什么可解釋的,就直接按照 Socket.IO 的 API 寫就完事了。
吾聞之吾師,有機(jī)械者必有機(jī)事,有機(jī)事者必有機(jī)心。機(jī)心存於胸中,則純白不備。
-- 《莊子·天地》
參考資料:
- 《HTML5 WebSocket權(quán)威指南》 機(jī)械工業(yè)出版社 2014 年 3 月第 1 版
 - http://www.ruanyifeng.com/blog/2017/05/websocket.html
 - https://www.cnblogs.com/hustskyking/p/websocket-with-node.html
 - https://www.cnblogs.com/jingmoxukong/p/7755643.html
 - https://zhuanlan.zhihu.com/p/23467317
 - https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
 
庫:
- https://socket.io/docs/
 - https://github.com/theturtle32/WebSocket-Node
 
















 
 
 












 
 
 
 