本文代码:本文代码:
1.HTTP的架构模式
1.1. HTTP的特点
2. 双向通信
2.1 轮询
2.2 长轮询
2.3 iframe流
2.4 EventSource流
2.4.1 浏览器端
2.4.2 服务端
3.websocket
3.1 websocket 优势
3.2 websocket实战
3.2.1 服务端
3.2.2 客户端
3.3 如何建立连接
3.3.1 客户端:申请协议升级
3.3.2 服务端:响应协议升级
3.3.3 Sec-WebSocket-Accept的计算
3.3.4 Sec-WebSocket-Key/Accept的作用
3.4 数据帧格式
3.4.1 数据帧格式
3.4.2 掩码算法
3.4.3 服务器实战
1. HTTP的架构模式
Http是客户端/服务器模式中请求-响应所用的协议,在这种模式中,客户端(一般是web浏览器)向服务器提交HTTP请求,服务器响应请求的资源。
1.1. HTTP的特点
- HTTP是半双工协议,也就是说,在同一时刻数据只能单向流动,客户端向服务器发送请求(单向的),然后服务器响应请求(单向的)。
- 服务器不能主动推送数据给浏览器。
2. 双向通信
Comet是一种用于web的推送技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有三种实现方式:轮询(polling) 长轮询(long-polling)和iframe流(streaming)。
2.1 轮询
- 轮询是客户端和服务器之间会一直进行连接,每隔一段时间就询问一次
- 这种方式连接数会很多,一个接受,一个发送。而且每次发送请求都会有Http的Header,会很耗流量,也会消耗CPU的利用率
**index.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>Document</title>
</head>
<body>
<div id="clock"></div>
<script>
let clock = document.querySelector("#clock");
setInterval(function () {
let xhr = new XMLHttpRequest();
xhr.open("GET", "/clock", true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
clock.innerHTML = xhr.responseText;
}
};
xhr.send();
});
</script>
</body>
</html>
**app.js**
let express = require("express");
let app = express();
// http://localhost:8000/
app.use(express.static(__dirname));
app.get("/clock", function (req, res) {
res.send(new Date().toLocaleString());
});
app.listen(8000);
2.2 长轮询
- 长轮询是对轮询的改进版,客户端发送HTTP给服务器之后,看有没有新消息,如果没有新消息,就一直等待
- 当有新消息的时候,才会返回给客户端。在某种程度上减小了网络带宽和CPU利用率等问题。
- 由于http数据包的头部数据量往往很大(通常有400多个字节),但是真正被服务器需要的数据却很少(有时只有10个字节左右),这样的数据包在网络上周期性的传输,难免对网络带宽是一种浪费
**index.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>Document</title>
</head>
<body>
<div id="clock"></div>
<script>
let clock = document.querySelector('#clock');
function send(){
let xhr = new XMLHttpRequest;
xhr.open('GET','/clock',true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
clock.innerHTML = xhr.responseText;
send();
}
}
xhr.send();
}
send();
</script>
</body>
</html>
**app.js**
let express = require("express");
let app = express();
// http://localhost:8000/
app.use(express.static(__dirname));
app.get("/clock", function (req, res) {
let $timer = setInterval(function () {
let date = new Date();
let seconds = date.getSeconds();
if (seconds % 5 === 0) {
res.send(date.toLocaleString());
clearInterval($timer);
}
}, 1000);
});
app.listen(8000);
2.3 iframe流
通过在HTML页面里嵌入一个隐藏的iframe,然后将这个iframe的src属性设为对一个长连接的请求,服务器端就能源源不断地往客户推送数据。
**index.html**
<!DOCTYPE html>
<html lang="en"><