本教程將創(chuàng)建一個基本的聊天應(yīng)用。 它幾乎不要求你事先了解 Node.JS 或 Socket.IO ,適合所有知識層次的用戶。
使用流行的 web 應(yīng)用技術(shù)棧 —— 比如 LAMP (PHP) —— 來編寫聊天應(yīng)用通常是很困難的。它包含了輪詢服務(wù)器以檢測變化,還要追蹤時間戳,并且這種實現(xiàn)是比較慢的。
大多數(shù)實時聊天系統(tǒng)通?;?socket 來構(gòu)建。 Socket 為客戶端和服務(wù)器提供了雙向通信機制。
這意味著服務(wù)器可以 推送 消息給客戶端。無論何時你發(fā)布一條消息,服務(wù)器都可以接收到消息并推送給其他連接到服務(wù)器的客戶端。
首先要制作一個 HTML 頁面來提供表單和消息列表。我們使用了基于 Node.JS 的 web 框架 express
。 請確保安裝了 Node.JS。
首先創(chuàng)建一個 package.json
來描述我們的項目。 推薦新建一個空目錄 (這里使用 chat-example
)。
{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"dependencies": {}
}
要保存 dependencies
信息, 可以用 npm install --save
:
npm install --save express@4.15.2
express 已經(jīng)安裝好了。我們現(xiàn)在新建一個 index.js
文件來創(chuàng)建應(yīng)用。
var app = require('express')();
var http = require('http').Server(app);
app.get('/', function(req, res){
res.send('<h1>Hello world</h1>');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
這段代碼作用如下:
app
作為 HTTP 服務(wù)器的回調(diào)函數(shù) (見第 2 行)。/
來處理首頁訪問。運行 node index.js
就可以看到如下畫面:
在瀏覽器中訪問 http://localhost:3000
:
目前在 index.js
中我們是通過 res.send
返回一個 HTML 字符串。 如果我們將整個應(yīng)用的 HTML 代碼都放到應(yīng)用代碼里,代碼結(jié)構(gòu)將變得很混亂。 替代的方法是新建一個 index.html
文件作為服務(wù)器響應(yīng)。
現(xiàn)在我們用 sendFile
來重構(gòu)之前的回調(diào):
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
index.html
內(nèi)容如下:
<!doctype html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
現(xiàn)在重啟進程 (按 Control+C ,然后再次運行 node index
) ,刷新頁面顯示如下:
Socket.IO 由兩部分組成:
socket.io
socket.io-client
開發(fā)環(huán)境下, socket.io
會自動提供客戶端。正如我們所見,到目前為止,我們只需要安裝一個模塊:
npm install --save socket.io
這會安裝模塊并添加依賴到 package.json
。在 index.js
文件中添加該模塊:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
我們通過傳入 http
(HTTP 服務(wù)器) 對象初始化了 socket.io
的一個實例。 然后監(jiān)聽 connection
事件來接收 sockets, 并將連接信息打印到控制臺。
在 index.html 的 </body>
標(biāo)簽中添加如下內(nèi)容:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
這樣就加載了 socket.io-client
。 socket.io-client 暴露了一個 io
全局變量,然后連接服務(wù)器。
請注意我們在調(diào)用 io()
時沒有指定任何 URL,因為它默認(rèn)將嘗試連接到提供當(dāng)前頁面的主機。
重新加載服務(wù)器和網(wǎng)站,你將看到控制臺打印出 “a user connected”。
嘗試打開多個標(biāo)簽頁,可以看到多條信息:
每個 socket 還會觸發(fā)一個特殊的 disconnect
事件:
io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
你可以多次刷新標(biāo)簽頁來查看效果:
Socket.IO 的核心理念就是允許發(fā)送、接收任意事件和任意數(shù)據(jù)。任意能被編碼為 JSON 的對象都可以用于傳輸。二進制數(shù)據(jù) 也是支持的。
這里的實現(xiàn)方案是,當(dāng)用戶輸入消息時,服務(wù)器接收一個 chat message
事件。index.html
文件中的 script
部分現(xiàn)在應(yīng)該內(nèi)容如下:
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js" rel="external nofollow" ></script>
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
});
</script>
在 index.js
中打印出 chat message
事件:
io.on('connection', function(socket){
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
結(jié)果應(yīng)該如以下視頻所示:
廣播
接下來的目標(biāo)就是讓服務(wù)器將消息發(fā)送給其他用戶。
要將事件發(fā)送給每個用戶,Socket.IO 提供了 io.emit
方法:
io.emit('some event', { for: 'everyone' });
要將消息發(fā)給除特定 socket 外的其他用戶,可以用 broadcast
標(biāo)志:
io.on('connection', function(socket){
socket.broadcast.emit('hi');
});
為了簡單起見,我們將消息發(fā)送給所有用戶,包括發(fā)送者。
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
在客戶端中,我們捕獲 chat message
事件,并將消息添加到頁面中?,F(xiàn)在客戶端代碼應(yīng)該如下:
<script>
$(function () {
var socket = io();
$('form').submit(function(){
socket.emit('chat message', $('#m').val());
$('#m').val('');
return false;
});
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
});
</script>
就這樣,聊天應(yīng)用就完成了,大約只有 20 行代碼! 最終效果如下:
課外練習(xí)
下面是一些可以做的優(yōu)化:
可以從 GitHub 獲取。
$ git clone https://github.com/socketio/chat-example.git
更多建議: