介紹
通常我們web使用的是http協議,但是 HTTP 協議有一個缺陷:通信只能由客戶端發起。
所以我們需要一個可以由服務端主動發出的協議,即WebSocket。
WebSocket是HTML5新增的一種通信協議,其特點是服務端可以主動向客戶端推送信息,客戶端也可以主動向服務端發送信息,是真正的雙向平等對話,屬於服務器推送技術的一種。
Socket.IO 是一個基於 Node.js 的實時應用程序框架,在即時通訊、通知與消息推送,實時分析等場景中有較為廣泛的應用。
socket.io 包含兩個部分:
- 服務器端(server):運行在 Node.js 服務器上
- 客戶端(client):運行在瀏覽器中
開啟服務
當然,socket.IO構架在一個nodejs服務上,這里開啟一個express服務。
創建文件夾socketIODemo,然后安裝
npm init -y
npm install express --save
之后在socketIODemo中創建文件index.js:
const express = require('express')
const app = express()
app.use(express.static(__dirname + '/public'));
app.listen(3000, () => console.log('Example app listening on port 3000!'))
創建靜態資源public/index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
overflow: hidden;
}
.chat {
float: left;
padding: 1em 1em 0 2em;
height: 100%;
width: 500px;
border-right: 1px solid #DA4;
overflow-y: scroll;
}
.inputpart {
float: left;
margin-left: 10px;
}
#userName {
font-size: 20px;
color: rgb(3, 57, 109);
}
</style>
</head>
<body>
<div class="chat">
<ul id="messages">
//聊天信息
</ul>
</div>
<div class="inputpart">
<div id="userName">
//用來展示用戶id
</div>
<form action="">
<input autocomplete="off" id="inpB" /><button id="say">Send</button>
</form>
</div>
</body>
</html>
此時開啟服務: node index, 訪問localhost:3000。

服務開啟!
使用socket.IO
安裝:
npm install socket.io --save
然后在index.js中注冊socket.io,並改為http監聽:
let http = require('http').Server(app)
const io = require('socket.io')(http)
app.use(express.static(__dirname + '/public'));
http.listen(3000, () => console.log('Example app listening on port 3000!'))
此時服務已改為WebSocket服務。
數據傳輸
服務端運行后會在根目錄動態生成socket.io的客戶端js文件,客戶端可以通過固定路徑/socket.io/socket.io.js添加引用。
在HTML中引用js文件,並調用:
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
$(function () {
var userName = '';
while ($('#userName').text().trim() === '') {
//設置用戶名
let promptName = prompt("請設置你的昵稱", "")
userName = promptName ? promptName + ':' : '未命名:';
$('#userName').text(userName);
}
let socket = io();
socket.on('connect', function () {
socket.emit('join', userName)
})
// 監聽系統消息
socket.on('sys', function (sysMsg) {
var message = '<div class="sysMsg">' + sysMsg + '</div>';
$('#messages').append(message);
});
})
</script>
這段代碼中,socket.on('connect', function () { })為默認監聽事件,socket.io 提供了默認事件(如:connect, message, disconnect)。也可以自定義。socket.emit('action');表示發送了一個action命令,命令是字符串的。
后台index.js文件中:
io.on('connection', function (socket) {
console.log('a user connected')
let userID = ''
socket.on('join', function (userName) {
userID = userName;
io.emit('sys', userID + '已加入房間');
console.log(userID + '加入了');
});
})
connection事件在客戶端成功連接到服務端時觸發,有了這個事件,我們可以隨時掌握用戶連接到服務端的信息。
當客戶端成功建立連接時,在connection事件的回調函數中,我們還是可以為socket注冊一些常用的事件,如:disconnect事件socket.on('disconnect',function(){...});,它在客戶端連接斷開是觸發,這時候我就知道用戶已經離開了。
重啟服務,打開多個窗口,查看聊天框內容:

下面添加聊天功能。
在HTML文件中添加事件監聽click:
$('#say').click((e) => {
e.preventDefault()
socket.send($("#inpB")[0].value)
$("#inpB")[0].value = ''
})
socket.on('msg', function (userName, userColor, msg) {
var message = ' <div class="message">' +
`<span class="user" style="font-size:1.5em; color: #${userColor}">` + userName + '</span>' +
' <span class="msg">' + msg + '</span>' +
'</div>';
$('#messages').append(message);
// 滾動條保持最下方
$('#messages').scrollTop($('#messages')[0].scrollHeight);
});
這段代碼中,首先監聽事件並將input中內容send回去;socket.on為自定義事件msg 用來接收后台發送來的其他人的發言。
socket.emit和socket.send的區別在stackoverflow中有一個解釋大意是說emit可以自定義事件,而send不可以,且只能以message接收。
后台index.js:
io.on('connection', function (socket) {
console.log('a user connected')
let userID = '', userColor =parseInt(Math.random() * 16777216).toString(16)
socket.on('join', function (userName) {
userID = userName;
io.emit('sys', userID + '已加入房間');
console.log(userID + '加入了');
});
socket.on('message', function (msg){
io.emit('msg', userID, userColor, msg)
})
})
為新的成員隨機匹配顏色,並將message監聽到的信息通過自定義為msg的事件emit出去。
此時,一個簡易聊天室已經完成。
讀者可以自行添加退出功能,或者設置多個房間。。。

