Socket.IO 是一個基於 Node.js 的實時應用程序框架,在即時通信、通知與消息推送,實時分析等場景中有較爲普遍的應用。javascript
WebSocket 的產生源於 Web 開發中日益增加的實時通訊需求,對比基於 http 的輪詢方式,它大大節省了網絡帶寬,同時也下降了服務器的性能消耗; socket.io 支持 websocket、polling 兩種數據傳輸方式以兼容瀏覽器不支持 WebSocket 場景下的通訊需求。css
WebSocket是HTML5最新提出的規範,雖然主流瀏覽器都已經支持,但仍然可能有不兼容的狀況,爲了兼容全部瀏覽器,給程序員提供一致的編程體驗,SocketIO將WebSocket、AJAX和其它的通訊方式所有封裝成了統一的通訊接口,也就是說,咱們在使用SocketIO時,不用擔憂兼容問題,底層會自動選用最佳的通訊方式。所以說,WebSocket是SocketIO的一個子集。html
首先要製做一個 HTML 頁面來提供表單和消息列表。咱們使用了基於 Node.JS 的 web 框架 express
。 請確保安裝了 Node.JS。前端
首先建立一個 package.json
來描述咱們的項目。 推薦新建一個空目錄 (這裏使用 chat-example
)。java
{ "name": "socket-chat-example", "version": "0.0.1", "description": "my first socket.io app", "dependencies": {} }
安裝相關依賴:node
npm install --save express@4.15.2 npm install --save socket.io
前端頁面:
index.htmljquery
<!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> <script src="/socket.io/socket.io.js"></script> <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" rel="external nofollow"></script> <script> // 請注意咱們在調用 io() 時沒有指定任何 URL,由於它默認將嘗試鏈接到提供當前頁面的主機。 /* var socket = io(); $('form').submit(function(){ alert($('#m').val()); socket.emit('chat message', $('#m').val()); $('#m').val(''); return false; }); */ $(function () { var socket = io(); $('form').submit(function(){ alert($('#m').val()); socket.emit('chat message', $('#m').val()); $('#m').val(''); return false; }); socket.on('chat message', function(msg){ $('#messages').append($('<li>').text(msg)); }); }); </script> </html>
服務端頁面 index.js:程序員
// 一、Express 初始化 app 做爲 HTTP 服務器的回調函數 var app = require('express')(); var http = require('http').Server(app) var io = require('socket.io')(http); // 二、定義了一個路由 / 來處理首頁訪問。 /* app.get('/', function(req, res){ res.send('<h1>Hello world</h1>'); }); */ app.get('/', function(req, res) { res.sendFile(__dirname + '/index.html'); }); // 三、使 http 服務器監聽端口 3000 http.listen(3000, function(){ console.log('listening on *:3000'); }) // ================== io 通訊 ===================== // 客戶端頁面打開時會和服務端創建鏈接 /* io.on('connection', function(socket){ console.log('a user connected'); }); */ // 每一個 socket 還會觸發一個特殊的 disconnect 事件: /* io.on('connection', function(socket){ console.log('a user connected'); socket.on('disconnect', function(){ console.log('user disconnected'); }); }); */ // 當用戶輸入消息時,服務器接收一個 chat message 事件 /* io.on('connection', function(socket){ console.log('a user connected'); socket.on('chat message', function(msg){ console.log('message: ' + msg); }); }); */ // 廣播,講消息發送給全部用戶,包括髮送者 io.on('connection', function(socket){ socket.on('chat message', function(msg){ // 發送消息給客戶端(全部客戶端都會收到) io.emit('chat message', msg); }); });
啓動服務:web
dell@DESKTOP-KPEE6OO MINGW64 /C/work/other/socket-chat $ node index.js listening on *:3000
訪問界面:express
先看界面:
服務端 index_plus.js
//建立一個http服務器 var app = require('http').createServer() // 把http封裝成io對象 var io = require('socket.io')(app) // 運行的服務器端口號 var PORT = 3000 var clientCount = 0 // 監聽端口 app.listen(PORT) io.on('connection', function (socket) { // 給每一個用戶取名字 clientCount++ socket.nickname = 'user' + clientCount // io.emit表明廣播,socket.emit表明私發 io.emit('enter', socket.nickname + ' comes in') // socket.on 表示服務器接收一個客戶端message 事件 socket.on('message', function (str) { // io.emit表示從服務端給客戶端發送一個消息 io.emit('message', socket.nickname + ' says: ' + str) }) // 客戶端斷開,自帶事件 socket.on('disconnect', function () { io.emit('leave', socket.nickname + ' left') }) })
客戶端:index_plus.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>聊天室</title> <!-- cdn --> <script src="https://cdn.bootcss.com/socket.io/2.3.0/socket.io.js"></script> </head> <body> <h1>聊天室</h1> <input id="sendTxt" type="text" /> <button id="sendBtn">發送</button> <div id="recv"></div> <script type="text/javascript"> var socket = io("ws://localhost:3000/"); //把接收的數據顯示到界面 function showMessage(str, type) { var div = document.createElement('div'); div.innerHTML = str; if (type == "enter") { div.style.color = 'blue'; } else if (type == "leave") { div.style.color = "red" } document.body.appendChild(div) } // 點擊以後發送 document.getElementById("sendBtn").onclick = function () { var txt = document.getElementById("sendTxt").value; if (txt) { // 文本不爲空發送 socket.emit('message', txt); } } // 第一個enter表明是進入事件,第二個enter爲了顯示須要 socket.on('enter', function (data) { showMessage(data, 'enter') }) socket.on('message', function (data) { showMessage(data, 'message') }) socket.on('leave', function (data) { showMessage(data, 'leave') }) </script> </body> </html>
啓動:
dell@DESKTOP-KPEE6OO MINGW64 /C/work/other/socket-chat $ node index_plus.js
io.on('connect', onConnect); function onConnect(socket){ // 發送給當前客戶端 socket.emit('hello', 'can you hear me?', 1, 2, 'abc'); // 發送給全部客戶端,除了發送者 socket.broadcast.emit('broadcast', 'hello friends!'); // 發送給同在 'game' 房間的全部客戶端,除了發送者 socket.to('game').emit('nice game', "let's play a game"); // 發送給同在 'game1' 或 'game2' 房間的全部客戶端,除了發送者 socket.to('game1').to('game2').emit('nice game', "let's play a game (too)"); // 發送給同在 'game' 房間的全部客戶端,包括髮送者 io.in('game').emit('big-announcement', 'the game will start soon'); // 發送給同在 'myNamespace' 命名空間下的全部客戶端,包括髮送者 io.of('myNamespace').emit('bigger-announcement', 'the tournament will start soon'); // 發送給指定 socketid 的客戶端(私密消息) socket.to(<socketid>).emit('hey', 'I just met you'); // 包含回執的消息 socket.emit('question', 'do you think so?', function (answer) {}); // 不壓縮,直接發送 socket.compress(false).emit('uncompressed', "that's rough"); // 若是客戶端還不能接收消息,那麼消息可能丟失 socket.volatile.emit('maybe', 'do you really need it?'); // 發送給當前 node 實例下的全部客戶端(在使用多個 node 實例的狀況下) io.local.emit('hi', 'my lovely babies'); };
提示: 下面的事件是保留的,不該該在應用中用做事件名稱:
error
connect
disconnect
disconnecting
newListener
removeListener
ping
pong