Open wieve opened 5 years ago
随着web技术的发展,使用场景和需求也越来越复杂,客户端不再满足于简单的请求得到状态的需求。实时通讯越来越多应用于各个领域。
HTTP是最常用的客户端与服务端的通信技术,但是HTTP通信只能由客户端发起,无法及时获取服务端的数据改变。只能依靠定期轮询来获取最新的状态。时效性无法保证,同时更多的请求也会增加服务器的负担。
WebSocket技术应运而生。
不同于HTTP半双工协议,WebSocket是基于TCP 连接的全双工协议,支持客户端服务端双向通信。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
WebSocket
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
WebSocket API
WebSocket对象一共支持四个消息 onopen, onmessage, onclose和onerror。
通过javascript可以快速的建立一个WebSocket连接:
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数url, 指定连接的URL。第二个参数 protocol是可选的,指定了可接受的子协议。
url
protocol
同http协议使用http://开头一样,WebSocket协议的URL使用ws://开头,另外安全的WebSocket协议使用wss://开头。
http://
ws://
wss://
Socket.onopen = function(evt) {};
Socket.onerror = function(evt) { };
Socket.onclose = function(evt) { };
Socket.onmessage = function(evt) { };
Socket.send();
WebSocket是跟随HTML5一同提出的,所以在兼容性上存在问题,这时一个非常好用的库就登场了——Socket.io。
socket.io封装了websocket,同时包含了其它的连接方式,你在任何浏览器里都可以使用socket.io来建立异步的连接。socket.io包含了服务端和客户端的库,如果在浏览器中使用了socket.io的js,服务端也必须同样适用。
socket.io是基于 Websocket 的Client-Server 实时通信库。
socket.io底层是基于engine.io这个库。engine.io为 socket.io 提供跨浏览器/跨设备的双向通信的底层库。engine.io使用了 Websocket 和 XHR 方式封装了一套 socket 协议。在低版本的浏览器中,不支持Websocket,为了兼容使用长轮询(polling)替代。
API文档
Socket.io允许你触发或响应自定义的事件,除了connect,message,disconnect这些事件的名字不能使用之外,你可以触发任何自定义的事件名称。
const socket = io("ws://0.0.0.0:port"); // port为自己定义的端口号 let io = require("socket.io")(http); io.on("connection", function(socket) {})
一、发送数据
socket.emit(自定义发送的字段, data);
二、接收数据
socket.on(自定义发送的字段, function(data) { console.log(data); })
一、全部断开连接
let io = require("socket.io")(http); io.close();
二、某个客户端断开与服务端的链接
// 客户端 socket.emit("close", {});
// 服务端 socket.on("close", data => { socket.disconnect(true); });
有时候websocket有如下的使用场景:1.服务端发送的消息有分类,不同的客户端需要接收的分类不同;2.服务端并不需要对所有的客户端都发送消息,只需要针对某个特定群体发送消息;
针对这种使用场景,socket中非常实用的namespace和room就上场了。
先来一张图看看namespace与room之间的关系:
服务端
io.of("/post").on("connection", function(socket) { socket.emit("new message", { mess: `这是post的命名空间` }); }); io.of("/get").on("connection", function(socket) { socket.emit("new message", { mess: `这是get的命名空间` }); });
客户端
// index.js const socket = io("ws://0.0.0.0:****/post"); socket.on("new message", function(data) { console.log('index',data); } //message.js const socket = io("ws://0.0.0.0:****/get"); socket.on("new message", function(data) { console.log('message',data); }
//可用于客户端进入房间; socket.join('room one'); //用于离开房间; socket.leave('room one');
io.sockets.on('connection',function(socket){ //提交者会被排除在外(即不会收到消息) socket.broadcast.to('room one').emit('new messages', data); // 向所有用户发送消息 io.sockets.to(data).emit("recive message", "hello,房间中的用户"); }
终于来到应用的阶段啦,服务端用node.js模拟了服务端接口。以下的例子都在本地服务器中实现。
node.js
先来看看服务端,先来开启一个服务,安装express和socket.io
express
socket.io
npm install --Dev express npm install --Dev socket.io
let app = require("express")(); let http = require("http").createServer(handler); let io = require("socket.io")(http); let fs = require("fs"); http.listen(port); //port:输入需要的端口号 function handler(req, res) { fs.readFile(__dirname + "/index.html", function(err, data) { if (err) { res.writeHead(500); return res.end("Error loading index.html"); } res.writeHead(200); res.end(data); }); } io.on("connection", function(socket) { console.log('连接成功'); //连接成功之后发送消息 socket.emit("new message", { mess: `初始消息` }); });
核心代码——index.html(向服务端发送数据)
<div>发送信息</div> <input placeholder="请输入要发送的信息" /> <button onclick="postMessage()">发送</button>
// 接收到服务端传来的name匹配的消息 socket.on("new message", function(data) { console.log(data); }); function postMessage() { socket.emit("recive message", { message: content, time: new Date() }); messList.push({ message: content, time: new Date() }); }
核心代码——message.html(从服务端接收数据)
socket.on("new message", function(data) { console.log(data); });
实时通讯效果
客户端全部断开连接
某客户端断开连接
namespace应用
加入房间
离开房间
npm install socket.io-client
const socket = require('socket.io-client')('http://localhost:port'); componentDidMount() { socket.on('login', (data) => { console.log(data) }); socket.on('add user', (data) => { console.log(data) }); socket.on('new message', (data) => { console.log(data) }); }
Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cache-Control: no-cache Connection: Upgrade Cookie: MEIQIA_VISIT_ID=1IcBRlE1mZhdVi1dEFNtGNAfjyG; token=0b81ffd758ea4a33e7724d9c67efbb26; io=ouI5Vqe7_WnIHlKnAAAG Host: 0.0.0.0:2699 Origin: http://127.0.0.1:5500 Pragma: no-cache Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Key: PJS0iPLxrL0ueNPoAFUSiA== Sec-WebSocket-Version: 13 Upgrade: websocket User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
请求包说明:
应答包说明:
Connection: Upgrade Sec-WebSocket-Accept: I4jyFwm0r1J8lrnD3yN+EvxTABQ= Sec-WebSocket-Extensions: permessage-deflate Upgrade: websocket
EIO: 3 transport: websocket sid: 8Uehk2UumXoHVJRzAAAA
WebSocket协议使用帧(Frame)收发数据,在控制台->Frames中可以查看发送的帧数据。
其中帧数据前的数字代表什么意思呢?
这是 Engine.io协议,其中的数字是数据包编码:
随着web技术的发展,使用场景和需求也越来越复杂,客户端不再满足于简单的请求得到状态的需求。实时通讯越来越多应用于各个领域。
HTTP是最常用的客户端与服务端的通信技术,但是HTTP通信只能由客户端发起,无法及时获取服务端的数据改变。只能依靠定期轮询来获取最新的状态。时效性无法保证,同时更多的请求也会增加服务器的负担。
WebSocket技术应运而生。
WebSocket概念
不同于HTTP半双工协议,WebSocket是基于TCP 连接的全双工协议,支持客户端服务端双向通信。
WebSocket
使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。在
WebSocket API
中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。实现
原生实现
WebSocket对象一共支持四个消息 onopen, onmessage, onclose和onerror。
建立连接
通过javascript可以快速的建立一个WebSocket连接:
以上代码中的第一个参数
url
, 指定连接的URL。第二个参数protocol
是可选的,指定了可接受的子协议。同http协议使用
http://
开头一样,WebSocket协议的URL使用ws://
开头,另外安全的WebSocket协议使用wss://
开头。收发消息
socket
WebSocket是跟随HTML5一同提出的,所以在兼容性上存在问题,这时一个非常好用的库就登场了——Socket.io。
socket.io封装了websocket,同时包含了其它的连接方式,你在任何浏览器里都可以使用socket.io来建立异步的连接。socket.io包含了服务端和客户端的库,如果在浏览器中使用了socket.io的js,服务端也必须同样适用。
socket.io是基于 Websocket 的Client-Server 实时通信库。
socket.io底层是基于engine.io这个库。engine.io为 socket.io 提供跨浏览器/跨设备的双向通信的底层库。engine.io使用了 Websocket 和 XHR 方式封装了一套 socket 协议。在低版本的浏览器中,不支持Websocket,为了兼容使用长轮询(polling)替代。
API文档
Socket.io允许你触发或响应自定义的事件,除了connect,message,disconnect这些事件的名字不能使用之外,你可以触发任何自定义的事件名称。
建立连接
消息收发
一、发送数据
二、接收数据
断开连接
一、全部断开连接
二、某个客户端断开与服务端的链接
room和namespace
有时候websocket有如下的使用场景:1.服务端发送的消息有分类,不同的客户端需要接收的分类不同;2.服务端并不需要对所有的客户端都发送消息,只需要针对某个特定群体发送消息;
针对这种使用场景,socket中非常实用的namespace和room就上场了。
先来一张图看看namespace与room之间的关系:
namespace
服务端
客户端
room
客户端
服务端
用socket.io实现一个实时接收信息的例子
终于来到应用的阶段啦,服务端用
node.js
模拟了服务端接口。以下的例子都在本地服务器中实现。服务端
先来看看服务端,先来开启一个服务,安装
express
和socket.io
安装依赖
构建node服务器
客户端
核心代码——index.html(向服务端发送数据)
核心代码——message.html(从服务端接收数据)
效果
实时通讯效果
客户端全部断开连接
某客户端断开连接
namespace应用
加入房间
离开房间
框架中的应用
npm install socket.io-client
分析webSocket协议
Headers
请求包
请求包说明:
应答包
应答包说明:
请求数据
Frames
WebSocket协议使用帧(Frame)收发数据,在控制台->Frames中可以查看发送的帧数据。
其中帧数据前的数字代表什么意思呢?
这是 Engine.io协议,其中的数字是数据包编码: