我正在参加「掘金·启航计划」
我们访问网站时,文件并不是直接请求的源服务器,而是请求的CDN分配的离你最近的服务器,达到最快加载的目的。
但是,假设一种情况:局域网内A和B用户都在访问我们网站,B访问我们网站需要某张图片,如果直接从A这边直接能拿到这张图片,那不是更快吗,而且还节省了CDN流量,这不就是企业要的降本增效吗
实现方案:
1、信令服务器为用户A匹配最优用户B,基于网络和地理(注意:如果双方p2p通信要依赖turn转发,那放弃,以免流量走到turn服务器)
2、webrct 打通数据通道,实现双方通信
3、service worker 拦截fetch请求静态资源,缓存已有资源,同步远端自身已有资源列表
4、fetch 拦截先判断远端用户是否有该资源,有就请求并组装分片,没有就正常CDN
5、远端数据通道收到资源请求后,分片发送资源
先回顾一下webrtc音视频聊天过程,service worker过程
音视频聊天过程
webrtc 基础例子请看WebRTC的p2p音视频小例子和源码 ,我们简单说下过程:
1、部署 coturn 服务,用做NAT穿透
2、编写信令服务器:用nodejs socket.io编写业务,主要是房间管理、人员进出等功能
3、重点是关注类 RTCPeerConnection
-> 新建pc对象,pc = new RTCPeerConnection(iceConfig)
-> 注册pc.onnegotiationneeded回调,用于本地媒体协商信息就绪后,向远端发送offer
-> 注册pc.onicecandidate回调,用于本地经过 coturn 服务器网络协商信息后,向远端发送candidate
-> 注册pc.ontrack回调,用于接收远端音视频流,绑定到video标签:remoteVideo.srcObject = mediaStream
4、结合pc和音视频流
-> 开启本地音视频设备:mediaStream = await navigator.mediaDevices.getUserMedia 获取音视频流
-> 绑定pc和音视频流:mediaStream.getTracks().forEach((track) => { pc.addTrack(track, mediaStream);});
5、创建datachannel做聊天和数据发送
-> 发送方创建数据通道:sendChannel = pc.createDataChannel("sendChannel");
-> 接收方监听数据通道:pc.ondatachannel = onsenddatachannel
-> 接收方在ondatachannel回调中监听接收数据:evt.channel.onmessage = onReceiveMessageCallback;
6、【连接发起方】创建本地offer
-> 创建本地offer:offer = pc.createOffer()
-> 设置本地offer:pc.setLocalDescription(offer)
-> 将offer通过信令服务器转发给远端接收方
7、【连接接收方】接收offer,创建本地answer
-> 接收offer,创建发起方offer对象:des = new RTCSessionDescription(offer)
-> 新建webtc对象:createPeerConnection
-> 设置发起方offer:pc.setRemoteDescription(des)
-> 创建answer对象:answer = pc.createAnswer()
-> 设置本地answer:pc.setLocalDescription(answer)
-> 将answer通过信令服务器回复给发起方
8、【连接发起方】接收并设置远程answer
-> 接受answer,创建接收方answer对象:des = new RTCSessionDescription(answer)
-> 设置接收方answer:pc.setRemoteDescription(des)
9、完成可音视频、聊天、发送数据
service worker过程
文章查看 我所知道的service worker,我们简单说下过程:
1、html注册sw.js
window.addEventListener("load", function () {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js");
}
});
2、sw.js初始化事件install、activate、fetch、message
self.addEventListener("install", async (event) => {
console.log("开始安装", event);
event.waitUntil(self.skipWaiting())
});
self.addEventListener("activate", async (event) => {
console.log("安装完成,开始启动", event);
event.waitUntil(self.clients.claim())
});
self.addEventListener("fetch", async (event) => {
console.log("运行中,拦截请求", event.request);
event.respondWith(fetch(event.request));
});
self.addEventListener("message", function (event) {
// 收到消息
console.log("收到消息html->sw", event.data);
// 发送消息
self.clients.matchAll().then(function (clients) {
clients.forEach((client) => {
client.postMessage({
action: "response message",
});
});
});
});
3、html js中注册监听 与 发送消息
// 收到消息
navigator.serviceWorker.addEventListener("message",function (event) {
console.log("收到消息sw->html", event.data);
}
);
// 发送消息
navigator.serviceWorker.controller.postMessage({
action: "the action event",
});