使用WebRTC搭建前端视频聊天室——点对点通信篇
WebRTC给我们带来了浏览器中的视频、音频聊天体验。但个人认为,它最实用的特性莫过于DataChannel——在浏览器之间建立一个点对点的数据通道。在DataChannel之前,浏览器到浏览器的数据传递通常是这样一个流程:浏览器1发送数据给服务器,服务器处理,服务器再转发给浏览器2。这三个过程都会带来相应的消耗,占用服务器带宽不说,还减缓了消息从发送到接收的时间。其实最理想的方式就是浏览器1直接与浏览2进行通信,服务器不需要参与其中。WebRTC DataChannel就提供了这样一种方式。
如果对WebRTC和DataChannel不太了解的同学,可以先阅读如下文章:
- WebRTC的RTCDataChannel
- 使用WebRTC搭建前端视频聊天室——信令篇
- 使用WebRTC搭建前端视频聊天室——入门篇
老刘和老姚
当然服务器完全不参与其中,显然是不可能的,用户需要通过服务器上存储的信息,才能确定需要和谁建立连接。这里通过一个故事来讲述建立连接的过程:
不如钓鱼去
一些背景:
- 老刘和老姚都住在同一个小区但不同的片区,小区很破旧,没有电话
- 片区相互隔离且片区门口有个保安,保安只认识自己片区的人,遇到不认识的人就需要查询凭证才能通过,而凭证需要找物业才能确定
- 门卫老大爷认识小区里的所有人但是不知道都住哪,有什么消息都可以在出入小区的时候代为传达
现在,老刘听说老姚钓鱼技术高超,想和老姚讨论钓鱼技巧。只要老刘和老姚相互之间知道对方的门牌号以及凭证,就可以串门了:
- 门卫老大爷认识老刘和老姚
- 老刘找物业确定了自己片区的出入凭证,将凭证、自己的门牌号以及意图告诉门卫老大爷,让其转交给老姚
- 老姚买菜归来遇到门卫老大爷,门卫老大爷将老刘的消息传达给老姚。于是老姚知道怎么去老刘家了
- 老姚很开心,他也找物业获取了自己小区的凭证,并将凭证、自己的门牌号等信息交给门卫老大爷,希望他传达给老刘
- 老刘吃早餐回来遇到门卫老大爷,老大爷把老姚的小区凭证、门牌号等信息告诉老刘,这样老刘就知道了怎么去老姚家了
老刘和老姚相互之间知道了对方的门牌号和小区出入凭证,他们相互之间有什么需要交流的直接串门就行了,消息不再需要门卫老大爷来代为传达了
换个角度
我们把角色做一个映射:
- 老刘:浏览器1
- 老姚:浏览器2
- 片区:不同网段
- 保安:防火墙
- 片区凭证:ICE candidate
- 物业:ICE server
- 门牌号:session description
- 门卫老大爷:server
于是乎故事就变成了这样:
- 浏览器1和浏览器2在server上注册,并保有连接
- 浏览器1从ice server获取ice candidate并发送给server,并生成包含session description的offer,发送给server
- server发送浏览器1的offer和ice candidate给浏览器2
- 浏览器2发送包含session description的answer和ice candidate给server
- server发送浏览器2的answer和ice candidate给浏览器1
这样,就建立了一个点对点的信道,流程如下所示:
礼物
故事
老刘和老姚已经可以相互串门了,经过一段时间的交流感情越来越深。老姚的亲友送了20斤葡萄给老姚,老姚决定送10斤给老刘。老姚毕竟年事已高,不可能一次带10斤。于是乎,老姚将葡萄分成了10份,每次去老刘家串门就送一份过去。
这里可以做如下类比:
1. 10斤葡萄:一个文件(尽管文件分片没有意义,葡萄分开还可以单独吃,但是实在找不到啥好的比喻了)
2. 分成10份:将文件分片,转成多个chunk
3. 老姚一次只能带一斤:datachannel每次传输的数据量不宜太大(找到最合适的大小)
这其实就是通过datachannel传输文件的方式,首先将文件分片,然后逐个发送,最后再统一的进行组合成一个新的文件
分片
通过HTML5的File API可以将type为file的input选中的文件读取出来,并转换成data url字符串。这也就为我们提供了很方便的分片方式:
var reader = new window.FileReader(file);
reader.readAsDataURL(file);
reader.onload = function(event, text) {
chunkify(event.target.result);//将数据分片
};
组合
通过datachannel发送的分片数据,我们需要将其进行组合,由于是data url字符串,在接收到所有包之后进行拼接就可以了。拼接完成后就得到了一个文件完整的data url字符串,那么我们如何将这个字符串转换成文件呢?
方案一:直接跳转下载
既然是个dataurl,我们直接将其赋值给window.location.href
自然可以下载,但是这样下载是没法设定下载后的文件名的,这想一想都蛋疼
方案二:通过a标签下载
这个原理和跳转下载类似,都是使用dataurl本身的特性,通过创建一个a标签,将dataurl字符串赋值给href属性,然后使用download确定下载后的文件名,就可以完成下载了。但是很快又有新问题了,稍微大一点的文件下载的时候页面崩溃了。这是因为dataurl有大小限制
方案三:blob
其实可以通过给a标签创建blob url的方式来进行下载,这个没有大小限制。但是我们手上是dataurl,所以需要先进行转换:
function dataURItoBlob(dataURI, dataTYPE) {
var binary = atob(dataURI.split(',')[1]),
array = [];
for (var i = 0; i < binary.length; i++) array.push(binary.charCodeAt(i));
return new Blob([new Uint8Array(array)], {
type: dataTYPE
});
}
获得blob后,我们就可以通过URL API来下载了:
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var blob = dataURItoBlob(data, 'octet/stream');
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
!moz && window.URL.revokeObjectURL(url);
a.parentNode.removeChild(a);
这里有几个点:
1. datachannel其实是可以直接传送blob的,但是只有ff支持,所以传data url
2. chrome下载是直接触发的,不会进行询问,firefox会先询问后下载,在询问过程中如果执行了revokeObjectURL
,下载就会取消,囧
升级
如我们所知,WebRTC最有特点的地方其实是可以传输getUserMedia获得的视频、音频流,来实现视频聊天。但事实上我们的使用习惯来看,一般人不会一开始就打开视频聊天,而且视频聊天时很消耗内存的(32位机上一个连接至少20M左右好像,也有可能有出入)。所以常见的需求是,先建立一个包含datachannel的连接用于传输数据,然后在需要时升级成可以传输视频、音频。
看看我们之前传输的session description,它其实来自Session Description Protocol。可以看到wiki上的介绍:
The Session Description Protocol (SDP) is a format for describing streaming media initialization parameters.
这意味着什么呢?我们之前建立datachannel是没有加视频、音频流的,而这个流的描述是写在SDP里面的。现在我们需要传输视频、音频,就需要添加这些描述。所以就得重新获得SDP,然后构建offer和answer再传输一次。传输的流程和之前一样,没什么区别。但这一次,我们不需要传输任何的ice candidate,这里我曾经遇到了坑,经过国外大大的点拨才明白过来。
from mattm: You do not need to send ICE candidates on an already established peer connection. The ICE candidates are to make sure the two peers can establish a connection through their potential NAT and firewalls. If you can already send data on the peer connection, ICE candidates will not do anything.
Peertc
我将datachannel和websocket组合,实现了一个构建点对点连接的库Peertc,它提供非常简洁的方式来建立连接和发送数据、文件和视频/音频流,详情见github。走过路过的记得star一下哦,有什么bug也非常希望能够提出来。
最后
WebRTC的点对点方式能够运用在很多场景:
- 如web qq这种Web IM工具,这就不说了
- 如象棋这种双人对战游戏,每一步的数据服务器时不关心的,所以完全可以点对点发送
- 一对一在线面试、在线教育,这其实是即时通信的一个业务方向
- 视频裸(),当我没说
使用WebRTC搭建前端视频聊天室——点对点通信篇的更多相关文章
- 使用WebRTC搭建前端视频聊天室——信令篇
博客原文地址 建议看这篇之前先看一下使用WebRTC搭建前端视频聊天室——入门篇 如果需要搭建实例的话可以参照SkyRTC-demo:github地址 其中使用了两个库:SkyRTC(github地址 ...
- 使用WebRTC搭建前端视频聊天室——入门篇
http://segmentfault.com/a/1190000000436544 什么是WebRTC? 众所周知,浏览器本身不支持相互之间直接建立信道进行通信,都是通过服务器进行中转.比如现在有两 ...
- WebRTC搭建前端视频聊天室——信令篇
这篇文章讲述了WebRTC中所涉及的信令交换以及聊天室中的信令交换,主要内容来自WebRTC in the real world: STUN, TURN and signaling,我在这里提取出的一 ...
- 使用WebRTC搭建前端视频聊天室——数据通道篇
本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...
- WebRTC搭建前端视频聊天室——数据通道篇
本文翻译自WebRTC data channels 在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成 ...
- 使用WebRTC搭建前端视频聊天室
在两个浏览器中,为聊天.游戏.或是文件传输等需求发送信息是十分复杂的.通常情况下,我们需要建立一台服务器来转发数据,当然规模比较大的情况下,会扩展成多个数据中心.这种情况下很容易出现很高的延迟,同时难 ...
- WebRTC实现网页版多人视频聊天室
因为产品中要加入网页中网络会议的功能,这几天都在倒腾 WebRTC,现在分享下工作成果. 话说 WebRTC Real Time Communication 简称 RTC,是谷歌若干年前收购的一项技术 ...
- 玩转Node.js(四)-搭建简单的聊天室
玩转Node.js(四)-搭建简单的聊天室 Nodejs好久没有跟进了,最近想用它搞一个聊天室,然后便偶遇了socket.io这个东东,说是可以用它来简单的实现实时双向的基于事件的通讯机制.我便看了一 ...
- 视频聊天室可以用php制作吗?
首先,告诉你单纯用php制作视频聊天室是实现不了的,需要配合其他技术手段一起操作,例如和FLASH配合,使用FLASH获取语音(FLASH可以获取访问端的设备,例如摄像头). PHP运行在服务器端,是 ...
随机推荐
- 山寨Unity3D?搜狐畅游的免费开源游戏引擎Genesis-3D
在CSDN上看到了<搜狐畅游发布3D游戏引擎Genesis-3D 基于MIT协议开源>(http://www.csdn.net/article/2013-11-21/2817585-cha ...
- .NET跨平台之旅:在生产环境中上线第一个运行于Linux上的ASP.NET Core站点
2016年7月10日,我们在生产环境中上线了第一个运行于Linux上的ASP.NET Core站点,这是一个简单的提供后端服务的ASP.NET Core Web API站点. 项目是在Windows上 ...
- Unit Of Work的设计
在DDD开发过程中,一个良好的Uow设计必不可少,我心目中的Uow设计应该具备以下几点: 1.有着良好的抽象,有着恰如其分的命名: 2.能够应付不同的组件,比如你的系统中可能会存在EfUnitOfWo ...
- Lesson 16 A polite request
Text If you park your car in the wrong place, a traffic policeman will soon find it. You will be ver ...
- Linux 中的数值计算和符号计算
不知道经常需要做科学计算的朋友们有没有这样的好奇:在 Linux 系统下使用什么工具呢?说到科学计算,首先想到的肯定是 Matlab,如果再说到符号计算,那就非 Mathematica 不可了.可惜, ...
- Entity Framework 6 Recipes 2nd Edition(10-9)译 -> 在多对多关系中为插入和删除使用存储过程
10-9. 在多对多关系中为插入和删除使用存储过程 问题 想要在一个无载荷的多对多关系中使用存储过程(存储过程只影响关系的连接表) 解决方案 假设有一个多对多关系的作者( Author)表和书籍( B ...
- Entity Framework 6 Recipes 2nd Edition(13-7)译 -> 返回只部分填充的实体
问题 你有一个实体里的某个属性很少被读取或和更新,这个属性因为比较大,所以读取和更新都需要付很大的代价.你想有选择的放置这个属性 解决方案 假设你有一个如Figure 13-9 所示的模型 Figur ...
- Hadoop相关日常操作
1.Hive相关 脚本导数据,并设置运行队列 bin/beeline -u 'url' --outputformat=tsv -e "set mapreduce.job.queuename= ...
- Atitit MATLAB 图像处理attilax总结
Atitit MATLAB 图像处理attilax总结 1.1. 下载 Matlab7.0官方下载_Matlab2012 v7.0 官方简体中文版-办公软件-系统大全.html1 1.2. Matla ...
- Hadoop的数据管理
Hadoop的数据管理,主要包括Hadoop的分布式文件系统HDFS.分布式数据库HBase和数据仓库工具Hive的数据管理. 1.HDFS的数据管理 HDFS是分布式计算的存储基石,Hadoop分布 ...