WebSocket API是下一代客戶端-服務(wù)器的異步通信方法。該通信取代了單個的TCP套接字,使用ws或wss協(xié)議,可用于任意的客戶端和服務(wù)器程序。WebSocket目前由W3C進(jìn)行標(biāo)準(zhǔn)化。WebSocket已經(jīng)受到Firefox 4、Chrome 4、Opera 10.70以及Safari 5等瀏覽器的支持。
WebSocket API最偉大之處在于服務(wù)器和客戶端可以在給定的時間范圍內(nèi)的任意時刻,相互推送信息。WebSocket并不限于以Ajax(或XHR)方式通信,因為Ajax技術(shù)需要客戶端發(fā)起請求,而WebSocket服務(wù)器和客戶端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允許跨域通信。
Ajax技術(shù)很聰明的一點是沒有設(shè)計要使用的方式。WebSocket為指定目標(biāo)創(chuàng)建,用于雙向推送消息。
ajax輪詢
客戶端:啦啦啦,有沒有新信息(Request)
服務(wù)端:沒有(Response)
客戶端:啦啦啦,有沒有新信息(Request)
服務(wù)端:沒有。。(Response)
客戶端:啦啦啦,有沒有新信息(Request)
服務(wù)端:你好煩啊,沒有啊。。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務(wù)端:好啦好啦,有啦給你。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務(wù)端:。。。。。沒。。。。沒。。。沒有(Response) —- loop
WebSocket
客戶端:啦啦啦,我要建立Websocket協(xié)議,需要的服務(wù):chat,Websocket協(xié)議版本:17(HTTP Request)
服務(wù)端:ok,確認(rèn),已升級為Websocket協(xié)議(HTTP Protocols Switched)
客戶端:麻煩你有信息的時候推送給我噢。。
服務(wù)端:ok,有的時候會告訴你的。
服務(wù)端:balabalabalabala
服務(wù)端:balabalabalabala
服務(wù)端:哈哈哈哈哈啊哈哈哈哈
服務(wù)端:笑死我了哈哈哈哈哈哈哈
socket.io
node.js提供了高效的服務(wù)端運(yùn)行環(huán)境,但是由于瀏覽器端對HTML5的支持不一,為了兼容所有瀏覽器,提供卓越的實時的用戶體驗,并且為程序員提供客戶端與服務(wù)端一致的編程體驗,于是socket.io誕生。Socket.io將Websocket和輪詢 (Polling)機(jī)制以及其它的實時通信方式封裝成了通用的接口,并且在服務(wù)端實現(xiàn)了這些實時機(jī)制的相應(yīng)代碼。也就是說,Websocket僅僅是 Socket.io實現(xiàn)實時通信的一個子集。那么,Socket.io都實現(xiàn)了Polling中的那些通信機(jī)制呢?
- Adobe? Flash? Socket
- AJAX long polling
- AJAX multipart streaming
- Forever Iframe
- JSONP Polling
使用socket.io制作聊天室
-
初始化
package.json
文件
在項目文件夾主目錄下執(zhí)行以下命令$ cnpm init -y
-
安裝對應(yīng)的包
-
express
服務(wù)器端路由的制作$ cnpm install --save express
?
-
socket.io
WebScoket的封裝庫$ cnpm install --save socket.io
-
-
編寫
server.js
服務(wù)器文件
創(chuàng)建server.js文件,作為服務(wù)器,使用express模塊進(jìn)行路由的編寫// 引入對應(yīng)的模塊 var app = require('express')(); var http = require('http').Server(app); // 訪問首頁即訪問index.html文件 app.get('/', function(req, res) { res.sendfile(__dirname + '/index.html'); }); // 設(shè)置端口以及回調(diào) http.listen(8888, function() { console.log('listening on *:3000'); });
-
編寫
index.html
文件<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta charset="utf-8"> <title></title> <style media="screen"> * { margin: 0; padding: 0; } html, body { width: 100%; height: 100%; } #messages { list-style-type: none; } #messages li { padding: 5px 10px; } #messages li:nth-child(odd) { background: #eee; } form { position: fixed; left: 0; right: 0; bottom: 0; height: 50px; background-color: #333; } form input { width: 80%; height: 40px; margin-top: 5px; border: none; } form button { width: 18%; height: 100%; background-color: cyan; border: none; } </style> </head> <body> <div class="container"> <ul id="messages"></ul> <form action=""> <input id="m" type="text" name="" value=""> <button type="submit">Send</button> </form> </div> </body> </html>
在終端執(zhí)行
node server.js
命令,即可運(yùn)行服務(wù)器,打開瀏覽器輸入http://localhost:8888
,即可看到效果-
在
server.js
中添加代碼,進(jìn)行socket.io
的數(shù)據(jù)傳輸事件的注冊,并重啟服務(wù)// 引入對應(yīng)的模塊 var app = require('express')(); var http = require('http').Server(app); // 新增代碼++++++++++++++++++++++++++ // 引入socket.io模塊 var io = require('socket.io')(http); // 訪問首頁即訪問index.html文件 app.get('/', function(req, res) { res.sendFile(__dirname + '/index.html'); }); // 新增代碼++++++++++++++++++++++++++ // 注冊事件,連接成功即可執(zhí)行 io.on('connection', function (socket) { console.log('鏈接已成功'); // 注冊事件,連接斷開即可執(zhí)行 io.on('disconnection', function (socket) { console.log('鏈接已斷開'); }); }); // 設(shè)置端口以及回調(diào) http.listen(8888, function() { console.log('listening on *:3000'); });
-
在
index.html
中添加代碼,創(chuàng)建一個socket
對象,即可觸發(fā)server.js
中注冊的事件<script src="/socket.io/socket.io.js"></script> <script type="text/javascript"> var socket = io(); </script>
刷新網(wǎng)頁的時候,即可看到如下的輸出結(jié)果:
lidaze-MBP-2:chat-room lidaze$ node server.js listening on *:3000 鏈接已成功 鏈接已斷開 鏈接已成功 鏈接已斷開 鏈接已成功
-
繼續(xù)
index.html
文件代碼的編寫<script src="/socket.io/socket.io.js"></script> <script src="https://code.jquery.com/jquery-1.11.1.js"></script> <script type="text/javascript"> $(function () { // 創(chuàng)建socket對象 var socket = io(); // 設(shè)置表單提交事件 $('form').submit(function () { // 使用socket觸發(fā)事件,通過傳參的方式將數(shù)據(jù)傳遞給服務(wù)器 socket.emit('chat message to server', $('#m').val()); $('#m').val(''); return false; }); }); </script>
-
當(dāng)點擊網(wǎng)頁中的發(fā)送按鈕時,會觸發(fā)socket觸發(fā)事件,進(jìn)行數(shù)據(jù)的傳遞,同樣的,也需要在服務(wù)器端進(jìn)行事件的監(jiān)聽
在server.js
中添加如下代碼,進(jìn)行數(shù)據(jù)的獲取// 注冊事件,連接成功即可執(zhí)行 io.on('connection', function (socket) { console.log('鏈接已成功'); // 新增代碼++++++++++++++++++++++++++ // 用于接收數(shù)據(jù)的監(jiān)聽 socket.on('chat message to server', function (msg) { console.log('message: ' + msg); }); // 注冊事件,連接斷開即可執(zhí)行 socket.on('disconnect', function (socket) { console.log('鏈接已斷開'); }); });
重啟服務(wù)器,在網(wǎng)頁中輸入內(nèi)容,然后點擊發(fā)送按鈕,即可看到控制臺中有內(nèi)容輸出
現(xiàn)在已經(jīng)實現(xiàn)了前端向后臺發(fā)送數(shù)據(jù),下面來實現(xiàn)服務(wù)器向瀏覽器返回數(shù)據(jù)。并重啟服務(wù)
// 用于接收數(shù)據(jù)的監(jiān)聽
socket.on('chat message to server', function (msg) {
console.log('message: ' + msg);
// 新增代碼++++++++++++++++++++++++++
// 使用io對象進(jìn)行事件的觸發(fā),將數(shù)據(jù)從服務(wù)器發(fā)送到瀏覽器
io.emit('chat message to browser', msg);
});
-
在
index.html
中接收服務(wù)器返回的數(shù)據(jù)// 注冊事件,用于接收瀏覽器返回的數(shù)據(jù) socket.on('chat message to browser', function (msg) { // 接收到數(shù)據(jù)后創(chuàng)建li標(biāo)簽,并拼接到頁面中 $('#messages').append($('<li>').text(msg)); });
-
代碼至此已經(jīng)編寫完畢,使用瀏覽器打開兩個網(wǎng)頁,均訪問
http://localhost:8888
地址,在一張網(wǎng)頁中輸入內(nèi)容,即可發(fā)現(xiàn)在另一個網(wǎng)頁中效果同步。這就是借助了WebSocket的及時通訊。除了實現(xiàn)瀏覽器端向服務(wù)器端發(fā)送數(shù)據(jù)外,服務(wù)器端也可以同時發(fā)送數(shù)據(jù)到瀏覽器中.