关于建设饮食与健康网站的意义,node.js 网站开发,网址大全123官方网站一汽奔腾,logo设计公司艺点意创怎么样背景#xff1a;
平时我们很少会需要使用到点对点单独的通讯#xff0c;即p2p,一般都是点对服务端通讯#xff0c;但p2p也有自己的好处#xff0c;即通讯不经过服务端#xff0c;从服务端角度这个省了带宽和压力#xff0c;从客户端角度#xff0c;通讯是安全#xff…背景
平时我们很少会需要使用到点对点单独的通讯即p2p,一般都是点对服务端通讯但p2p也有自己的好处即通讯不经过服务端从服务端角度这个省了带宽和压力从客户端角度通讯是安全且快速的当然有些情况下可能速度并不一定快。那么如何实现p2p呢
解决办法
webrtc的RTCPeerConnection就实现了p2p的功能使用RTCPeerConnection需要理解一些概念什么是信令信令交换的过程信令服务器。
信令
2个设备需要通讯就需要知道对方的在互联网上的公开地址一般情况下2个设备都是不会直接拥有一个公网的ip地址所以他们之间的通讯就需要如何在公网找到自己的方式路由信息告诉对方通常这个信息都是临时的并非永久当对方获取到这个信息后就可以通过网络找到彼此的实际路由路径从而进行通讯这个信息就是信令位置信息。
信令的交换过程
假设2个设备p1要和p2进行通讯
1.p1发起邀请阶段
const offer await p1.createOffer();//创建邀请信令
await p1.setLocalDescription(offer);//设置为本地信令send(JSON.stringify(offer));//把邀请信令发送给对方至于怎么发送一般是需要一个第3方的信令服务器来转发这个信息
2.p2收到邀请阶段 当收到p1发起的有邀请信令offer后
await p2.setRemoteDescription(new RTCSessionDescription(JSON.parse(offer)));//设置为远端的信令const answer await p2.createAnswer();//创新一个应答信令告诉p1我的位置
await pc.setLocalDescription(answer);//设置我的位置send(JSON.stringify(answer ));将位置信息发送给p1
3.p1收到应答信息阶段
await p2.setRemoteDescription(new RTCSessionDescription(JSON.parse(answer )));//设置为远端的信令
4.处理onicecandidate事件确认要不要通讯 await p2.addIceCandidate(new RTCIceCandidate(JSON.parse(candidate)));
完成上述几个阶段正常来说就能开始通讯了 数据通讯DataChannel的使用
发送端
// 创建PeerConnection对象
const pc new RTCPeerConnection();// 创建DataChannel
const dataChannel pc.createDataChannel(myDataChannel);// 监听DataChannel的open事件
dataChannel.onopen () {console.log(DataChannel已打开);
};// 监听DataChannel的error事件
dataChannel.onerror (error) {console.error(DataChannel错误:, error);
};// 监听DataChannel的close事件
dataChannel.onclose () {console.log(DataChannel已关闭);
};// 发送文本消息
function sendMessage(message) {dataChannel.send(message);
}// 发起PeerConnection连接
// ...// 在某个事件触发时调用sendMessage()发送消息
// sendMessage(Hello, world!);
接收端
// 创建PeerConnection对象
const pc new RTCPeerConnection();// 监听DataChannel的open事件
pc.ondatachannel (event) {const dataChannel event.channel;// 监听DataChannel的message事件dataChannel.onmessage (event) {const message event.data;console.log(接收到消息:, message);};// 监听DataChannel的error事件dataChannel.onerror (error) {console.error(DataChannel错误:, error);};// 监听DataChannel的close事件dataChannel.onclose () {console.log(DataChannel已关闭);};
};
datachannel的用法发送端和接收端用法是一样的只是接收端需要通过 onicecandidate的事件才能获取到。
单页面完整demo
!DOCTYPE html
html
headtitleWebRTC Demo/title
/head
bodyh1WebRTC Demo/h1button onclickstart()Start/buttonbutton onclickcall()Call/buttonbutton onclickhangup()Hang Up/buttonbutton onclicksendMessage()send/buttonbrbrtextarea idlocalDesc/textareabrbrtextarea idremoteDesc/textareabrbrtextarea idmessage/textareabrbrtextarea idreceived/textareascriptlet localConnection, remoteConnection,dataChannel,receiveChannel;function start() {localConnection new RTCPeerConnection();remoteConnection new RTCPeerConnection();localConnection.onicecandidate e {if (e.candidate) {console.log(localConnection.onicecandidate)remoteConnection.addIceCandidate(e.candidate);}};remoteConnection.onicecandidate e {if (e.candidate) {console.log(remoteConnection.onicecandidate)localConnection.addIceCandidate(e.candidate);}};localConnection.oniceconnectionstatechange e {console.log(Local ICE connection state change:, localConnection.iceConnectionState);};remoteConnection.oniceconnectionstatechange e {console.log(Remote ICE connection state change:, remoteConnection.iceConnectionState);};remoteConnection.ondatachannel e {console.log(ondatachannel,e)receiveChannel e.channel;receiveChannel.onmessage e {console.log(onmessage,e.data)document.getElementById(received).value e.data \n;};};dataChannel localConnection.createDataChannel(dataChannel);dataChannel.onopen e {console.log(onopen)console.log(Data channel opened);};dataChannel.onclose e {console.log(onclose)console.log(Data channel closed);};dataChannel.onmessage event {console.log(onmessage,event.data)};
}async function call() {console.log(createOffer)const offer await localConnection.createOffer();await localConnection.setLocalDescription(offer);await remoteConnection.setRemoteDescription(offer);console.log(createAnswer)const answer await remoteConnection.createAnswer();await remoteConnection.setLocalDescription(answer);await localConnection.setRemoteDescription(answer);document.getElementById(localDesc).value localConnection.localDescription.sdp;document.getElementById(remoteDesc).value remoteConnection.localDescription.sdp;}async function hangup() {await localConnection.close();await remoteConnection.close();localConnection null;remoteConnection null;}function sendMessage() {const message document.getElementById(message).value;//const dataChannel localConnection.createDataChannel(dataChannel);dataChannel.send(message);console.log(send,message)}/script
/body
/html
不同页面demo信令交换过程手动操作
!DOCTYPE html
html
headtitleWebRTC 文本消息发送/title
/head
bodytextarea idxx/textareatextarea idxx2/textareatextarea idxx3/textareadivlabel formessage消息/labelinput typetext idmessage /button onclicksendMessage()发送/buttonbutton onclicksendOffer()邀请/buttonbutton onclickhandleAnswer()接收远程信令/buttonbutton onclickhandleCandidate()接收candidate/buttonbrbutton onclickhandleOffer()接收邀请/button/divdiv idchat/divscriptlet pc;let dataChannel;// 创建本地PeerConnection对象function createPeerConnection() {pc new RTCPeerConnection();// 创建数据通道dataChannel pc.createDataChannel(chat);// 监听收到消息事件dataChannel.onmessage event {console.log(event.data)const message event.data;displayMessage(message);};// 监听连接状态变化事件dataChannel.onopen () {displayMessage(连接已建立);};dataChannel.onclose () {displayMessage(连接已关闭);};pc.ondatachannel (e){console.log(ondatachannel,e)};// 监听ICE候选事件pc.onicecandidate e {if (e.candidate) {document.getElementById(xx3).value JSON.stringify(e.candidate);}};pc.oniceconnectionstatechange e {console.log(Local ICE connection state change:, pc.iceConnectionState);};}createPeerConnection()// 处理信令function handleSignal(signal) {switch (signal.type) {case offer:handleOffer(signal.offer);break;case answer:handleAnswer(signal.answer);break;case candidate:handleCandidate(signal.candidate);break;}}async function sendOffer(){let desc await pc.createOffer()pc.setLocalDescription(desc); document.getElementById(xx).value JSON.stringify(desc)console.log(desc)}// 处理Offer信令async function handleOffer() {await pc.setRemoteDescription(new RTCSessionDescription(JSON.parse(document.getElementById(xx2).value)));let answer await pc.createAnswer()await pc.setLocalDescription(answer);document.getElementById(xx).value JSON.stringify(answer)}// 处理Answer信令async function handleAnswer() {// 设置远端描述let answer new RTCSessionDescription(JSON.parse(document.getElementById(xx2).value))await pc.setRemoteDescription(answer);}// 处理ICE候选信令async function handleCandidate() {try {await pc.addIceCandidate(new RTCIceCandidate(JSON.parse(document.getElementById(xx2).value)));} catch (error) {console.error(添加ICE候选失败:, error);}}// 发送消息function sendMessage() {const messageInput document.getElementById(message);const message messageInput.value;dataChannel.send(message);displayMessage(我 message);messageInput.value ;}// 显示消息function displayMessage(message) {const chatDiv document.getElementById(chat);const messageP document.createElement(p);messageP.textContent message;chatDiv.appendChild(messageP);}/script
/body
/html