WebRTC RTCDataChannel

WebRTC需要STUN服务器和TURN服务器,其中STUN主要负责获取客户端的ip地址和端口号(ipv4和ipv6的地址均可获得),此方案不适用于对称型Nat,因此需要TURN服务器对无法使用穿透的对称nat用户进行中级转发服务。但TURN并非必须的。STUN配置方法见WebRTC-在阿里云基于coturn搭建STUN\TURN服务器 - 简书

//首先需要创建RTCPeerConnection对象
const pc = new RTCPeerConnection({
	'iceServers':[{
		'urls':'stun:xxx.com:3478'    //此处使用的是域名,也可以使用ip   'urls':'stun:127.0.0.1:3479'    
		'credential':'123456'    //此处是密码,如果stun配置则输入        'username':'test'    //stun配置的验证用户名
	},/*此处可以绑定多个stun或turn*/]
})
    
//创建数据通道,用于进行数据收发
const dataChannel = pc.createDataChannel('此处输入一个字符串作为全局唯一标识符',{
	ordered:true,    //该值指示发送的数据是否保证有序
    negotiated:true,    //该值指示DataChannel两种协商模式,具体可以去搜素一下,此处采取true  Out-of-band协商方式,默认采取false  In-band协商
	id: 0,    //一个连接可以创建多个通道,该值指示每个通道的标识。如果negotiated为true,该值必须声明并保证两端值相同,否则无法进行数据通信
})
    
//此处绑定回调,用于处理iceCandidate,也就处理收集到的候选者
//所谓候选者即客户端与客户端之间进行通信时,所必需的ip地址和端口号等信息
//候选者并非唯一,因为两客户端在同一局域网下、在广域网下两种情况会需要不同的ip定位,而对于对称nat等无法穿透的情况下,需要的是turn中继服务器,
//对于具有ipv6的客户端来说又可以使用ipv6进行网络定位,因此候选者通常有多个。
//下面的回调方法在每次收集到一个候选者时将会返回,在此进行处理并交由信令服务器转发
pc.onicecandidate = function(candidate){
	//此处进行candidate转发业务
    //不通浏览器返回的类型可能不同,此处使用Chrome/Edge
    send(candidate.candidate)
}
    
//整个WebRTC的业务流程应当是:1.创建RTCPeerConnection → 2.创建dataChannel → 3.绑定onicecandidate → 4.绑定本地会话描述 → 5.收集候选者 → 6.绑定远程会话描述
//上述流程中2、3可以调换,但3、4不能调换,5的业务流程无需手动调用实现,在客户端调用setLocalDescription(即4.绑定本地会话描述,下面实现)时会自动开始收集并调用3绑定的回调函数
    
//WebRTC有两处协商:一个是媒体数据协商(sdp),一个是网络协商(iceCandidate),前者用于保证两客户端发送的数据格式等一致(对于媒体通信来说所需要的视频音频的编解码器等),后者用于携带ip、port保证两端能够建立正确的网络连接
//对于媒体会话协商,双端的代码并不完全一样,下面分开来看
//一端为发起端
pc.CreateOffer().then((offer)=>{
    //将本地媒体会话发送给对端
    send(offer)
    //发送的同时需要将本地媒体会话绑定到本地
    pc.setLocalDescription(offer)    
})
    
recv().then((dataAnswer)=>{
    pc.setRemoteDescription(dataAnswer)    
})
//*********************************************
//一端为被动端  此处pc为被动端pc
recv().then((dataOffer)=>{
    //设置远程媒体会话描述
    pc.setRemoteDescription(dataOffer)
    //然后由此创建本地媒体会话描述
	let answer = pc.CreateAnswer()
    pc.setLocalDescription(answer)
	send(answer)    //发给对端作为其远程会话描述
})
    
    
//调用setLocalDescription后,WebRTC开始自动收集候选项,此时需要将其发送给对端,下面代码双端通用
recv().then((iceCandidate)=>{
	pc.addIceCandidate(iceCandidate);
})
    
//至此已经完成两客户端连接,可以开始通信。
//整体流程(假设AB两客户端):1.AB端创建RTCPeerConnection、2.AB端创建dataChannel、3.AB端设置onicecandidate回调函数、4.A调用CreateOffer创建sdp、5.A绑定本地sdp并将sdp发送给B、6.A开始收集候选项,每收到一个候选者就执行一次回调函数,该回调函数应当将候选项发送给B、7.B收到sdp将其绑定到远端sdp,调用CreateAnswer创建本地sdp。并绑定到本地,将其发送给A、8.B开始收集候选项、9.A收到B的sdp将其设为远程,A获取B的候选项并调用addIceCandidate、B获取A的候选项并调用addIceCandidate
    
//dataChannel相关方法
dataChannel.onerror = (error)=>{
	console.log(error)
}
    
dataChannel.onopen = (event=>{
	console.log('open')
	dataChannel.send('hi~')
)
    
dataChannel.onmessage = (event)=>{
	console.log(event.data)
}

对于WebRTC来说,STUN和TURN都并不是必需的,二者均不使用时依旧会收集局域网的ipv4和ipv6候选项,其中ipv4仅能在局域网内使用,但是ipv6可以被外网访问到,因此对于面向目标为ipv6群体的网站来说,其实并不需要STUN进行额外的候选项获取服务。对于需要STUN的用户(即ipv4用户)来说,绝大多数情况下其为对称nat(SNAT)较难实现穿透,此时就必须使用TURN进行中继转发,但使用TURN进行的业务就不再是真正意义上的P2P,因而会使得服务器带宽压力线性增长。同时,候选者可以根据来源分为三种:主机候选者、反射候选者、中继候选者。主机候选者即前面提到的局域网ipv4和ipv6(此处的ipv6公网可以访问得到),该候选者会被优先考虑,即优先局域网通信,之后是采用ipv6,如果非局域网并且没有开启ipv6,则需要考虑反射候选者(即STUN获取到的ipv4地址),如果STUN没有配置或由于对称nat无法建立连接则最终会考虑TURN(如果没有配置TURN则会返回null)转发。

注意,谷歌官方的stun测试网址无法进行候选项获取,可能是因为具有用户名和密码的验证。

关于WebRTC IP泄露的问题:对于Chrome、Edge(以及其他Chrome内核的浏览器,其他浏览器请自行测试)等浏览器,两类候选者(主机候选者、反射候选者)安全性不同,其中主机候选者采用mDNS协议,能够避免ip泄露的问题(用户可以自行打印候选项,得到的ip地址类似 dbd415d1-afa1-4eb0-a4b7-ba553fd74e4f.local,该值即使用mDNS协议处理过的ip地址),而STUN服务器获取到的候选项(即反射候选者)则会得到实际的IP地址。由此观之,ipv6能够不使用STUN并且避免了最坏的情况(TURN,SNAT对于大多数国内家庭wifi用户来说也是经常出现的情况),并且能够避免ip泄露。

谷歌浏览器关闭mDNS方法:地址栏输入 chrome://flags/#enable-webrtc-hide-local-ips-with-mdns 设为Disabled即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值