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