共计 4287 个字符,预计需要花费 11 分钟才能阅读完成。
一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 WebSocket 和 HTTP |
3.1(短)轮询(Polling) |
3.2 长轮询 |
3.3 WebSocket |
3.4 两者比对 |
四 Socket.io |
4.1 服务端代码 |
4.2 客户端代码 |
4.3 小结 |
五 参考文献 |
二 前言
返回目录
WebSocket
是 HTML5
新增的一种全双工通信协议,客户端和服务器基于 TCP 握手连贯胜利后,两者之间就能够建设持久性的连贯,实现双向数据传输。
三 WebSocket 和 HTTP
返回目录
咱们晓得 HTTP
协定是一种单向的网络协议,在建设连贯后,它容许客户端向服务器发送申请资源后,服务器才会返回相应的数据,而服务器不能被动推送数据给客户端。
过后为什么这样设计呢?假如一些不良广告商被动将一些信息强行推送给客户端,这不得不说是一个劫难。
所以当初咱们要做股票的实时行情,或者获取火车票的残余票数等,就须要客户端和服务器之间重复地进行 HTTP
通信,客户端一直地发送 GET
申请,去获取以后的实时数据。
上面介绍几种常见的形式。
3.1(短)轮询(Polling)
返回目录
短轮询模式下,客户端每隔一段时间向服务器发送 HTTP
申请。
服务器收到申请后,将最新的数据发回给客户端。
这种状况下的弊病是非常明显的:某个时间段服务器没有更新内容,然而客户端每隔一段时间发送申请来询问,而这段时间内的申请是有效的。
这就导致了网络带宽的节约。
3.2 长轮询
返回目录
长轮询模式下,客户端向服务器发出请求,服务器并不一定会立刻回应客户端,而是查看数据是否有更新。
如果数据更新了的话,那就立刻发送数据给客户端;如果没有更新,那就放弃这个申请,期待有新的数据到来,才将数据返回给客户端。
如果服务器长时间没有更新,那么一段时间后,申请变会超时,客户端收到音讯后,会立刻发送一个新的申请给服务器。
当然这种形式也有弊病:当服务器向客户端发送数据后,必须期待下一次申请能力将新的数据收回,这样客户端接管新数据就有一个最短时间距离。
如果服务器更新频率较快,那么就会呈现问题。
3.3 WebSocket
返回目录
基于后面的状况,为了彻底解决服务器被动向客户端发送数据的问题。
W3C
在 HTML5
中提供了一种让客户端与服务器之间进行全双工通信的网络技术 WebSocket
。
WebSocket
基于 TCP
协定,是一种全新的、独立的协定,与 HTTP
协定兼容却不会融入 HTTP
协定,仅仅作为 HTML5
的一部分。
3.4 两者比对
返回目录
基于下面,小伙伴们大略理解了 WebSocket
的原因了,这里再总结比照一下 HTTP
和 WebSocket
。
- 相同点
- 都须要建设
TCP
连贯 - 都属于七层协定中的应用层协定
- 不同点
HTTP
是单向数据流,客户端向服务器发送申请,服务器响应并返回数据;WebSocket
连贯后能够实现客户端和服务器双向数据传递,除非某一端断开连接。HTTP
的url
应用http//
或者https//
结尾,而WebSocket
的url
应用ws//
结尾
四 Socket.io
返回目录
咱们先来看 WebSocket
的一个应用形式:
const ws = new WebSocket("ws//:xxx.xx", [protocol])
ws.onopen = () => {ws.send('hello')
console.log('send')
}
ws.onmessage = (ev) =>{console.log(ev.data)
ws.close()}
ws.onclose = (ev) =>{console.log('close')
}
ws.onerror = (ev) =>{console.log('error')
}
WebSocket
实例化后,前端能够通过下面介绍的办法进行对应的操作,看起来还是蛮简略的。
然而,如果想齐全搭建一个 WebSocket
服务端比拟麻烦,又浪费时间。
所以:Socket.io
基于 WebSocket
,加上轮询机制以及其余的实时通信方面的内容,实现的一个库,它在服务端实现了实时机制的响应代码。
也就是说,WebSocket
仅仅是 Socket.io
实现通信的一个子集。
因而,WebSocket
客户端连贯不上 Socket.io
服务端,Socket.io
客户端也连不上 WebSocket
服务端。
上面咱们解说下如何实现一个简略的聊天。
4.1 服务端代码
返回目录
package.json
{
"devDependencies": {
"express": "^4.15.2",
"socket.io": "^2.3.0"
}
}
index.js
let express = require('express');
let app = express();
let server = require('http').createServer(app);
let io = require('socket.io')(server);
let path = require('path');
app.use('/', (req, res, next) => {res.status(200).sendFile(path.resolve(__dirname, 'index.html'));
});
// 开启 socket.io
io.on('connection', (client) => {
// 如果有新客户端进来,显示 ID
console.log(` 客户端 ID:${client.id}`);
// 监听客户端的输出信息
client.on('channel', (data) => {console.log(` 客户端 ${client.id} 发送信息 ${data}`);
io.emit('broadcast', data);
});
// 判断客户端是否敞开
client.on('disconnect', () => {console.log(` 客户端敞开:${client.id}`);
});
});
server.listen(3000, () => {console.log('服务监听 3000 端口');
});
如上,咱们间接通过 npm i
装置依赖包后,间接通过 node index.js
能够开启服务。
当然,如果小伙伴们想手动装包,执行上面命令即可:
npm i express socket.io express -D
4.2 客户端代码
返回目录
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Socket.io</title>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.slim.js"></script>
</head>
<body>
<input type="text" id="input">
<button id="btn">send</button>
<div id="content-wrap"></div>
<script>
window.onload = function () {
let inputValue = null;
// 连贯 socket.io
let socket = io('http://localhost:3000');
// 将创立的信息以增加 p 标签的模式展现成列表
socket.on('broadcast', data => {let content = document.createElement('p');
content.innerHTML = data;
document.querySelector('#content-wrap').appendChild(content);
})
// 设置输入框的内容
let inputChangeHandle = (ev) => {inputValue = ev.target.value;}
// 获取输入框并监听输出
let inputDom = document.querySelector("#input");
inputDom.addEventListener('input', inputChangeHandle, false);
// 当用户点击发送信息的时候,进行数据交互
let sendHandle = () => {socket.emit('channel', inputValue);
}
let btnDom = document.querySelector("#btn");
btnDom.addEventListener('click', sendHandle, false);
// 打页面卸载的时候,告诉服务器敞开
window.onunload = () => {btnDom.removeEventListener('click', sendHandle, false);
inputDom.removeEventListener('input', inputChangeHandle, false);
}
};
</script>
</body>
</html>
4.3 小结
返回目录
Socket.io
不仅反对 WebSocket
,还反对许多种轮询机制以及其余实时通信形式,并封装了通用的接口。
这些形式蕴含 Adobe Flash Socket
、Ajax
长轮询、Ajax multipart streaming
、长久 Iframe
、JSONP
轮询等。
换句话说,当 Socket.io
检测到以后环境不反对 WebSocket
时,可能主动地抉择最佳的形式来实现网络的实时通信。
这样,咱们就对 WebSocket
有肯定的理解,面试的时候就不慌了。
五 参考文献
返回目录
- [x] websocket 与 Socket.IO 介绍【浏览倡议:10min】
- [x] WebSocket 与 Socket.IO【浏览倡议:10min】
- [x] Websocket 和 Socket.io 的区别及利用【浏览倡议:20min】
jsliang 的文档库由 梁峻荣 采纳 常识共享 署名 - 非商业性应用 - 雷同形式共享 4.0 国内 许可协定 进行许可。<br/> 基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/> 本许可协定受权之外的应用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处取得。