PON网络数据传输方式

那在OLT与POS之间其实只有一根光纤,如何实现上下行的数据在一根光纤中传输呢?

【答案】:划分不同的车道,即规划不同的波长。

【解析】:在PON网络中,上下行通信所采用的波长是不一样的,比如EPON/GPON同属于1G PON技术,它们下行波长规划的是1490nm,上行波长规划的是1310nm,互不影响,完全可以实现双向全双工的通信。此外,还有广电的CATV业务,单独的波长规划时1550nm。

到这里,有小伙伴又有疑问了:

为什么规定下行波长是1490nm,上行是1310nm,而不是反过来呢?

【答案】:成本考虑。

【解析】:标准制定的时候,1310nm的光器件已经相对来说比较成熟,成本较低,而1490nm成本较高。PON是一个点到多点的架构,那么我们自然要将成本比较低器件放在多点侧的发端,这样才会大量的降低PON网络初期的部署成本。

下面我们继续回到PON网络的数据传输的介绍。PON下行采用广播的方式传输数据,上行采用的是TDMA的方式传输数据。一连串的疑问又来了:

PON下行为何采用广播的方式传输数据呢?

【答案】:因为简单实用。

【解析】:PON的下行方向是指从OLT到ONU的这个方向,这个方向发端与收端的数量对比关系是“1对多”的关系,那我们自然就会选择用广播的方式来发送数据,因为这样最省事。同时,下行因受限于无源分路器的物理特性,PON口发出的数据经过无源分路器后平均分配至每一分路,其无源物理特性无法控制某一分路的通与不通,仅能实现单纯分路功能,故下行依据物理分路特性实现了被动广播的现象。

PON下行采用广播,每个ONU都能收到其他ONU的数据,如何保证数据安全?

【答案】:ONU主动过滤,同时数据有加密。

【解析】:一方面,ONU会根据相应的过滤条件主动过滤属于自己的数据,如通过ONU ID(GEM-PORT ID)过滤接收属于自己的数据;另一方面,OLT给每个ONU发送的数据会进行加密(如GPON的AES-128),且加密的密钥是由每个ONU产生并发给OLT的,ONU不会知道其他ONU的密钥,故也难解密属于其他ONU的数据。

动图封面

PON上行为何采用TDMA的方式传输数据呢?

【答案】:实现多ONU同时传输数据,公平竞争。

【解析】:PON的上行方向跟下行方向是反的,即指ONU到OLT的方向,这个方向发端与收端的数量对比关系是“多对一”的关系。既然是“多对一”的关系,肯定就不能让每个ONU想当然的发送数据了,否则就会存在同波长光信号叠加(如GPON的1310nm),OLT接收后也无法读取数据,出现误码帧或未知帧提示,并将其丢弃。

所以这种情况就必须要有一种仲裁机制,来保护我们的上行数据传输不发生冲突。这个仲裁机制便是TDMA,它将上行链路分成不同的时隙,再将这些时隙根据需要分给不同的ONU,ONU在属于自己的时隙发送数据。

动图封面

因此,我们这里也看到,ONU的发光时间严格受OLT指定,它是不会主动发光的,也不会长时间发光的。一旦某个ONU主动发光了或者长时间发光了,这个ONU就是一个“流氓ONU”,会影响整个PON口下的业务。

视频切片加密后播放

最近网上大学想下载一个视频,但下载下来的ts文件不能播放,把m3u8文件下载下来一看里面有

#EXT-X-KEY:METHOD=AES-128,URI="https://kc.zhixueyun.com/hls/9fd5d229-3b75-11e7-b669-44a84230d603",IV=0xd9221589c954ff5538bdc9af225e3e9e

里面的EXT-X-KEY:METHOD=AES-128说明服务器方在把文件切片成ts文件然后播放时进行了加密,所以我们先把m3u8这个文件下载下来,看有多少个ts文件,然后要把uri这个文件和所有ts文件下载下来(迅雷批量下载)放一个文件夹,把上面文件中的uri地址改成本地地址,用迅雷影音就可以直接打开m3u8文件播放。

一般hls视频流加密我们用到常见的一种是防盗链(严格来讲这不属于加密) , 也就是说给 m3u8 和 ts 文件的url动态生成一个 token , 比如这个:

http://www.cuplayer.com/m3u8/hunan/desc.m3u8?stream_id=hunan<m=1410595018&lkey=8bc1e0fe35f6321ef560f8ccffb70e5d&path=59.49.42.14,58.59.3.9,58.59.3.51&platid=10&splatid=1015&tag=live&cips=127.0.0.1&ext=m3u8&sign=live_tv

这个url是随着很多参数动态变化的,比如时间,用户id、ip地址,内容id , 导致你无法使用这个url盗链,这种方式可以防止其他网站直接使用你的url来观看或者一般用户的下载。

而ts文件的url 也需要加请求token , 会变化成类似 http://server/file.ts?token=xxxx 的方式, 这样的话, ts文件的磁盘存储位置不用变化,但是url是可以变化的(可以用query string方式,也可以用 url rewrite 方式), 注意因为url是m3u8生成的,意味着m3u8文件是动态生成而并非静态文件

另一种就是我上面说的DRM加密,用来给ts内容加密, m3u8有这个tag: #EXT-X-KEY

下面是网上找的如何把一个mp4视频使用ffmpeg视频切片并加密和视频AES-128加密后播放

创建加密文件:将一个mp4视频文件切割为多个ts片段,并在切割过程中对每一个片段使用AES-128 加密,最后生成一个m3u8的视频索引文件;

1.加密用的key(文件则保存当前目录)

指令:openssl rand -base64 20 > enc.key

提示打开文件本次生成的 n4DHLx7kMPeewvW3dGlm5i/EE8I=

2.另一个是iv(生成一段字符串,记下来):

指令:openssl rand -hex 16

提示打印出本次生成的682f5033538cf71567e1bdb38f5f9a07

新建一个文件enc.keyinfo 内容格式如下:
Key URI # enc.key的路径,使用http形式
Path to key file # enc.key文件
IV # 上面生成的iv

实例:
http://edu.gamagou.cn/enc.key
/usr/share/nginx/html/enc.key
682f5033538cf71567e1bdb38f5f9a07

  1. ffmpeg加密指令:

/home/programs/video/ffmpeg/ffmpeg -y -i /home/programs/video/test/123.mp4 -hls_time 12 -hls_key_info_file /home/programs/video/conf/enc.keyinfo -hls_playlist_type vod -hls_segment_filename “file%d.ts” playlist.m3u8

加密后的文件形式:

EXTM3U
EXT-X-VERSION:3
EXT-X-TARGETDURATION:12
EXT-X-MEDIA-SEQUENCE:0
EXT-X-PLAYLIST-TYPE:VOD
EXT-X-KEY:METHOD=AES-128,URI=”https://edu.amin.cc/enc.key”,IV=0x15de9b7283a69d7ef11f6f12e488fbb7
EXTINF:12.040000,

file0.ts

EXTINF:10.440000,

file1.ts

EXT-X-ENDLIST
  1. 播放部分:
    jq控件:hls.js
    手册:https://www.bootcdn.cn/hls.js/readme/

播放页面:

<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<!-- Or if you want a more recent canary version -->
<!-- <script src="https://cdn.jsdelivr.net/npm/hls.js@canary"></script> -->
<video id="video"></video>
<script>
  var video = document.getElementById('video');
  if(Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource('https://替换你的文件路径.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
  });
 } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = 'https://替换你的文件路径.m3u8';
    video.addEventListener('loadedmetadata',function() {
      video.play();
    });
  }
</script>

完成。


裸纤、专线、SDH、MSTP、MSTP+、OTN、PTN、IP-RAN

(一)裸纤
裸纤也叫裸光纤,运营商提供一条纯净光纤线路,中间不经过任何交换机或路由器,只经过配线架或配线箱做光纤跳纤,可以理解成运营商仅仅提供一条物理线路。实际项目中,裸光纤应用较多,比如某大学两个校区,相隔大概20KM,租用运营商裸光纤实现两个校区互联。可以理解成通过一根很长的光纤连接两个校区,拓扑图也简单,直连即可,如图所示:

最早两个校区均有运营商互联网出口,采用两套认证系统,管理维护麻烦,后续升级改造,两个校区租用运营商裸光纤,将两个校区互联起来,相当于将老校区网络作为一个子模块,接入到新校区,与新校区有机融合到一起,实现统一运营和管理。

租用运营商裸纤价格较高,一般按照公里收费,记得某项目租用20km裸纤,费用为20万/年,5年线路费用就是100万。有人可能会问,既然裸纤线路这么贵,为什么不自己拉一根光纤,连接两个校区,买光纤和工人布线施工的成本也用不了这么多呀!的确如此,但不是你想拉光纤就能拉的。国家法律明文规定,只有运营商、军队、市政等几个部门可以在公共区域破土施工,学校/医院/政府这类单位,在自己单位园区内部(也就是围墙内)随便怎么挖,没人会管,但到公共区域施工就不允许了,犯法!

裸光纤应用场景还很多,比如教育城域网,会租用运营商裸光纤,实现教育局与辖区各学校互联,将网络出口统一到教育局,从而实现教育资源共享,统一审计等功能,某县教育网城域网拓扑如图,租用运营商裸光纤实现学校与教育局互联,最后通过教育局网络统一网络出口访问互联网。

另外,在平安城市/视频专网/雪亮工程等项目中,也经常租用运营商裸纤,实现前端摄像头视频流量回传,如下为公安部统计,全国视频专网链路类型,35%采用裸纤。(注:交警前端电子警察一般采用裸纤回传,有钱就任性,而平安城市摄像头采用PON链路较多)

(二)专线
专线一般分三层专线和二层专线,三层专线一般是指MPLS V.P.N,这是CCIE RS方向考试的重点内容,说实话比较难,基本只在金融、电子政务等行业应用,一般人接触不上。我们日常说的专线基本指二层专线,二层专线相当于运营商给了你“一根线”,你两端连接PC,分别配置192.168.1.1/24和192.168.1.2/24,能直接ping通。效果看似跟裸纤差不多,但与裸纤的实质区别是: 裸纤中间不经过任何路由器交换机设备,运营商给你的是真实的一根线,而专线中间经过运营商的各类路由器交换机设备,只是运营商给你模拟出来了一根线,让你感觉跟裸纤效果差不多,至于专线的底层技术,这个是CCIE ISP运营商方向研究的内容,大部分人无需搞得那么透。

如果租用运营商裸纤,只要光纤不被挖断,运营商内部交换机路由器等设备故障,不会影响业务。如果你租用的光纤被挖断了,那就没办法了,业务肯定受影响。如果租用运营商专线,运营商设备出问题,可能影响用户业务,反而光纤被挖断,不一定会影响业务,因为运营商骨干网采用环形设计,传统SDH和新的OTN底层都会有环网,所以论可靠性而言,专线可靠性稍高。笔者今年经历的一个大型雪亮工程项目,一个主数据中心,七个分中心,考虑使用什么链路互联。最早规划使用裸纤互联,但后来考虑到可靠性,改成了租用运营商二层专线互联。当然,使用裸纤也有别的优势,比如带宽自主可控,如下图所示,你需要10G带宽,只需要在交换机上插10G光模块,需要40G带宽在交换机上插40G光模块,在交换机上插100G光模块,自然就有100G带宽。但是如果向运营商租用10G或40G专线,价格高得吓人!

专线可以看成是运营商的一种产品,底层实现技术很多,有SDH、MSTP、PTN、OTN等。下面为大家介绍一下运营商网络常见术语。

(三)SDH和MSTP
要明白SDH,首先要说TDM,TDM是时分复用,就是将一个标准时长(1 秒)分成若干段小的时间段(8000),每一个小时间段(1/8000=125us)传输一路信号;SDH系统就是传统的电路调度,电路调度是以TDM为基础,。早年的网络都是传输语音的,说白了电话网络的基础是TDM。
在SDH大红大紫的时候,另一场战争以太网和ATM(不是取款机哟)大战中,以太网取得全面胜利,从而以太网大行其道,其中又以IP最为强势,导致今天很多业务侧都IP 化了,服务器、PC、摄像头都得配置IP地址吧!
早年运营商骨干网SDH是大红人(运营商早期就是靠装电话挣钱),而园区网内部以太网是另一个大红人(上网数据通过以太网承载),能否合作一下?于是一拍即合,MSTP诞生,运营商骨干部分依旧使用SDH时分复用,但运营商甩给用户的链路接口采用园区网流行的以太网接口,也就是10M、100M、1G、10G这样的标准以太网接口,而不是155M、622M、2.5G这类POS/CPOS接口。

在合资公司MSTP中股份分配不太均匀:SDH 占股70%,以太网占股20%,其它包括ATM占股10%,掌权的还是SDH,内核还是TDM。以太网和ATM因为股权问题,都没有拿出像样的东西,只是须有其表(提供相应接口而已)毕竟早期网络,还是语音为主,数据为辅,但现在完全颠倒,以太网当然不干了,也就有了后来的WDM、OTN、IP-RAN。(就像一家公司,最牛逼的某销售贡献了90%的业绩,他还不出去自己创业,他是傻么?)

(四)波分WDM
随着互联网的大力普及,电脑、手机、电视等终端都能上网了,带宽的需求急剧增加,电信运营商们赚钱的机会来了,但挑战也来了,以前1*155M可以供好上千人打电话,现在人们需要打电话同时还要上网,家庭宽带都300M光纤入户了,带宽需求增长和现网资源出现矛盾,承载语音的TDM骨干网已经完全不能满足海量音视频传输要求。
要解决这个矛盾,专家们思考良久,某天看到二环路高架桥,恍然大悟,如果将网络传输也划分多个通道,也能提升传输性能。于是波分产生,波分WDM 就是将多个波道的信号放到同一条光纤中进行传送。WDM得到重用后,各地纷纷仿效,现在的WDM不仅在城市主干道里使用(城域波分),还用在跨市、跨省道路上(长途波分)。

裸光纤+波分的效果对比
如图使用传统裸光纤,目前商用较多的是100G光模块,那么链路最大100G。裸光纤两端部署波分设备,带宽惊人,线路带宽直接可以到4T甚至更高,单条光纤目前实验室最高波分速率是36T。当然,波分设备特别贵,不是一般单位买得起,波分设备厂商主要有华为、烽火等,客户为运营商、公安、BAT这类单位居多。

(五)OTN
OTN(OpticalTransportNetwork,光传送网)
WDM波分技术优势是带宽大,大得惊人。当然也存在一些问题,最突出的是实时流量监测和重点业务保障没有很好的措施。
SDH 笑道:小样儿,容量那么大,你监测和管理上还是有问题吧?
WDM 回应道:我容量确实比你大得多,但管理这方面的确没你们做得好;
于是他们握手言欢,优势互补,一个全新的制度诞生了—OTN。
所以简单的说:OTN=WDM+SDH

我们对以前的红人SDH在江湖的发展做了详细的描述,现在的SDH也只相当于OTN掌门下的一个堂主而已了,那么另一位红人以太网它现在发展的如何呢?

(六)MSTP+
由于先前MSTP成立时,股权分配不均,有很多遗留问题,以太网仅占20%,导致现在以太网严重不满意,毕竟现在网络上IP流量占了90%以上,为了安抚这个“销量”占公司90%的“销售”,SDH 集团研究后推出MSTP+(也叫Hybrid MSTP),50/50股权分配,进一步提升以太网在公司的地位,也不为一种好的补偿措施。

(七)IP-RAN和PTN
以太网现在声势越来越大,再加上又有MPLS 助阵,逐渐有了可以抗衡SDH的实力,面对MSTP+50%的股份分配,以太网并不高兴,发誓要有所改观……

为了对抗SDH阵营,以太网大力发展自己的势力,走农村包围城市的策略,先将末端IP化(终端PC、摄像头、打印机都得配IP)。同时建立以IP+以太网主导的骨干网,相当于自己开公司,创业了。以太网阵营,自由散漫惯了,现在出现了两种大的分歧:
第一种:认为我们自己成立的运输公司不让SDH的客户(TDM业务)上车,如果一定要进来,必须改头换面-伪装(仿真),同时我们没有时间上的保证(无时间同步),我们纯粹为我们以太网服务,我们的公司名叫IP-RAN;
第二种:认为我们应该吸收一些SDH的客户,SDH经营了这么多年,它的客户还是很多的(还有很多TDM业务需求),同样进来后还是要改头换面-伪装(仿真),然后再我们的帮派里活动,出帮派后再去掉伪装还原成自己原来的模样,这个公司取名叫PTN。
无论哪种方式,伪装-易容术总少不了,随后就开发了PWE3 易容术(CCIE ISP运营商方向重点讲的内容,一般人了解即可)。

(八)总结
MSTP+(Hybrid MSTP)可以看做是SDH向以太网的妥协方案,不得已而为之。随着相互学习融合,IP-RAN和PTN现在已趋于一致,差别不大了,所谓:分久必合合久必分!它们是IP/以太网向SDH发起的全面挑战,现在看来它们是胜利了。

现状:

第一档OTN专线现在多用于政企专网。相比IPRAN和PTN,OTN和互联网物理隔离,资源独享,是现阶段电信最好的端到端专线业务。

第二档是IPRAN云专线,接入端IPRAN,骨干CN2。

第三档是pon专线,直接从olt的pon出纤。

说到这,IP-RAN/PTN战胜了SDH,也就是数通战胜了传统通信,运营商骨干网完全IP化

流媒体视频基础 MSE 入门 & FFmpeg 制作视频预览缩略图和 fmp4

如果检查主流视频网站的视频,就会发现网站的 video 元素的 src 属性都是 blob 开头的字符串。

为什么视频链接前面会有 blob 前缀?这是因为视频网站使用了这篇文章要讲的 MSE 来播放视频。

Media Source Extensions

虽然 video 很强大,但是还有很多功能 video 并不支持,比如直播,即时切换视频清晰度,动态更新音频语言等功能。

MSE(Media Source Extensions)就来解决这些问题,它是 W3C 的一种规范,如今大部分浏览器都支持。

它使用 video 标签加 JS 来实现这些复杂的功能。它将 videosrc 设置为 MediaSource 对象,然后通过 HTTP 请求获取数据,然后传给 MeidaSource 中的 SourceBuffer 来实现视频播放。

如何将 MediaSourcevideo 元素连接呢?这就需要用到 URL.createObjectURL 它会创建一个 DOMString 表示指定的 File 对象或 Blob(二进制大对象) 对象。这个 URL 的生命周期和创建它的窗口中的 document 绑定。

const video = document.querySelector('video')
const mediaSource = new MediaSource()

mediaSource.addEventListener('sourceopen', ({ target }) => {
    URL.revokeObjectURL(video.src)
    const mime = 'video/webm; codecs="vorbis, vp8"'
    const sourceBuffer = target.addSourceBuffer(mime) // target 就是 mediaSource
    fetch('/static/media/flower.webm')
        .then(response => response.arrayBuffer())
        .then(arrayBuffer => {
            sourceBuffer.addEventListener('updateend', () => {
                if (!sourceBuffer.updating && target.readyState === 'open') {
                    target.endOfStream()
                    video.play()
                }
            })
            sourceBuffer.appendBuffer(arrayBuffer)
        })
})

video.src = URL.createObjectURL(mediaSource)
复制代码

addSourceBuffer 方法会根据给定的 MIME 类型创建一个新的 SourceBuffer 对象,然后会将它追加到 MediaSourceSourceBuffers 列表中。

我们需要传入相关具体的编解码器(codecs)字符串,这里第一个是音频(vorbis),第二个是视频(vp8),两个位置也可以互换,知道了具体的编解码器浏览器就无需下载具体数据就知道当前类型是否支持,如果不支持该方法就会抛出 NotSupportedError 错误。更多关于媒体类型 MIME 编解码器可以参考 RFC 4281

这里还在一开始就调用了 revokeObjectURL。这并不会破坏任何对象,可以在 MediaSource 连接到 video 后随时调用。 它允许浏览器在适当的时候进行垃圾回收。

视频并没有直接推送到 MediaSource 中,而是 SourceBuffer,一个 MeidaSource 中有一个或多个 SourceBuffer。每个都与一种内容类型关联,可能是视频、音频、视频和音频等。

视频格式

HTML5 标准指定时,想指定一种视频格式作为标准的一部分,所有浏览器都必须实现。但是对于 H.264 视频编码各个厂商产生的争论,主要是 H.264 非常强大(高画质、高压缩比、成熟的编解码器…),但是它也要高昂的授权费。Mozilla 这类免费浏览器,并没有从其开发的浏览器上获得直接收入,但是让 H.264 加入标准,它就要支付相应的授权费,所有认为是不可接受的。于是后来放弃了视频格式指定的统一,浏览器厂商可以自由选择支持的格式。

不过现在所有主流浏览器都支持 H.264 编码格式的视频,所有选择视频编码时优先选择 H.264 编码。

MediaSource API

MediaSource 属性

属性描述
sourceBuffers返回包含 MediaSource 所有 SourceBufferSourceBufferList 对象
activeSourceBuffers上个属性的子集,返回当前选择的视频轨道,启用的音频规定和显示或隐藏的文本轨道
duration获取或者设置当前媒体展示的时长,负数或 NaN 时抛出 InvalidAccessError
readyState 不为 openSourceBuffer.updating 属性为 true 时抛出 InvalidStateError
readyState表示 MediaSource 的当前状态

readyState 有以下值:

  • closed 未附着到一个 media 元素上
  • open 已附着到一个 media 元素并准备好接收 SourceBuffer 对象
  • ended 已附着到一个 media 元素,但流已被 MediaSource.endOfStream() 结束

MediaSource 方法

方法描述
addSourceBuffer(mime)根据给定 MIME 类型创建一个新的 SourceBuffer 对象,将它追加到 MediaSource 的 SourceBuffers 列表中
removeSourceBuffer(sourceBuffer)移除 MediaSource 中指定的 SourceBuffer。如果不存在则抛出 NotFoundError 异常
endOfStream(endOfStreamError)向 MediaSource 发送结束信号,接收一个 DOMString 参数,表示到达流末尾时将抛出的错误
setLiveSeekableRange(start, end)设置用户可以跳跃的视频范围,参数是以秒单位的 Double 类型,负数等非法参数会抛出异常
clearLiveSeekableRange清除上次设置的 LiveSeekableRange

其中 addSourceBuffer 可能会抛出一下错误:

错误描述
InvalidAccessError提交的 mimeType 是一个空字符串
InvalidStateErrorMediaSource.readyState 的值不等于 open
NotSupportedError当前浏览器不支持的 mimeType
QuotaExceededError浏览器不能再处理 SourceBuffer 对象

endOfStream 的参数可能是如下两种字符串:

  • network 终止播放并发出网络错误信号
  • decode 终止播放并发出解码错误信号

MediaSource.readyState 不等于 open 或有 SourceBuffer.updating 等于 true,调用 endOfStream 会抛出 InvalidStateError 异常。

它还有一个静态方法

静态方法描述
isTypeSupported(mime)是否支持指定的 mime 类型,返回 true 表示可能支持并不能保证

MediaSource 事件

错误描述
sourceopenreadyStateclosedendedopen
sourceendedreadyStateopenended
sourceclosereadyStateopenendedclosed

SourceBuffer API

SourceBuffer 通过 MediaSource 将一块块媒体数据传递给 meida 元素播放。

SourceBuffer 属性

属性描述
mode控制处理媒体片段序列,segments 片段时间戳决定播放顺序,sequence 添加顺序决定播放顺序,
MediaSource.addSourceBuffer() 中设置初始值,如果媒体片段有时间戳设置为 segments,否则 sequence
自己设置时只能从 segments 设置为 sequence,不能反过来。
updating是否正在更新,比如 appendBuffer()remove() 方法还在处理中
buffered返回当前缓冲的 TimeRanges 对象
timestampOffset控制媒体片段的时间戳偏移量,默认是 0
audioTracks返回当前包含的 AudioTrack 的 AudioTrackList 对象
videoTracks返回当前包含的 VideoTrack 的 VideoTrackList 对象
textTracks返回当前包含的 TextTrack 的 TextTrackList 对象
appendWindowStart设置或获取 append window 的开始时间戳
appendWindowEnd设置或获取 append window 的结束时间戳

append window 是一个时间戳范围来过滤 append 的编码帧。在范围内的编码编码帧允许添加到 SourceBuffer,之外的会被过滤。

SourceBuffer 方法

方法描述
appendBuffer(source)添加媒体数据片段(ArrayBufferArrayBufferView)到 SourceBuffer
abort中断当前片段,重置段解析器,可以让 updating 变成 false
remove(start, end)移除指定范围的媒体数据

SourceBuffer 事件

方法描述
updatestartupdatingfalse 变为 true
updateappendremove 已经成功完成,updatingtrue 变为 false
updateendappendremove 已经结束,在 update 之后触发
errorappend 时发生了错误,updatingtrue 变为 false
abortappendremoveabort() 方法中断,updatingtrue 变为 false

注意事项

  1. 几乎所有 MediaSource 方法调用或设置属性,在 MediaSource.readyState 不是 open 时会抛出 InvalidStateError 错误,应该在调用方法或设置属性前查看当前状态,即使是在事件回调中,因为可能在回调执行之前改变了状态。此外 endOfStream 方法还会因为 SourceBufferupdatingtrue 时也抛出该异常
  2. 在调用 SourceBuffer 方法或设置属性时,应该检查 SourceBuffer 是否为 false
  3. MediaSource.readyState 的值是 ended 时,调用 appendBuffer()remove() 或设置 modetimestampOffset 时,将会让 readyState 变为 open,并触发 sourceopen 事件,所有应该要有处理多个 sourceopen 事件准备

Initialization Segment

如果随便找一个 mp4 文件,使用上面那个例子播放,就会发现播放不了。这是因为 SourceBuffer 接收两种类型的数据:

  1. Initialization Segment 视频的初始片段,其中包含媒体片段序列进行解码所需的所有初始化信息。
  2. Media Segment 包含一部分媒体时间轴的打包和带时间戳的媒体数据。

MSE 需要使用 fmp4 (fragmented MP4) 格式,MP4 文件使用面向对象格式其中包含 Boxes (或叫 Atoms),可以使用 这个网站 查看 Mp4 文件信息。

这是一个普通的 MP4 文件,可以看到它有一个很大的 mdat (电影数据)box

这是 fragmented MP4 的截图,ISO BMFF 初始化段定义为单个文件类型框(File Type Box ftyp)后跟单个电影标题框(Movie Header Box moov),更多信息可以查看 ISO BMFF Byte Stream Format

moov 只包含一些视频基础的信息(类型,编码器等),moof 存放样本位置和大小,moof 框后都有一个 mdat,其中包含如前面的 moof 框中所述的样本。

要查看当前视频是不是 fmp4,就可以看 ftyp 后面是不是跟着 moov,然后是 moof mdat 对就行了。

要将普通 MP4 转换成 FMP4 可以下载 Bento4。然后用命令行输入如下命令就可以了。

mp4fragment ./friday.mp4 ./friday.fmp4
复制代码

Bento4 /bin 目录中有非常多好用的 mp4 工具,/utils 目录中都是 python 实用脚本。

工具

除了上面介绍的 Bento4,还有很多其他好用的工具。有了下面的工具,就可以快速制作 MSE 实践的视频素材了。

chrome://media-internals/

chrome://media-internals/ 是 chrome 浏览器用来调试多媒体的工具,直接在地址栏输入该值就可以。

Shaka Packager

Shaka Packager 是 Google 出的一个小巧视频工具,它只有 5M 左右,它可以用来查看视频信息,分离音频和视频,还支持 HLS 和 DASH。

它的命令行使用格式如下:

packager stream_descriptor[,stream_descriptor] [flags]
复制代码

比如用它查看视频信息:

packager in=friday.mp4 --dump_stream_info # 查看视频信息

File "friday.mp4":
Found 2 stream(s).
Stream [0] type: Audio
 codec_string: mp4a.40.2 # 音频的编码器字符串
 time_scale: 44100
 duration: 271360 (6.2 seconds)
 is_encrypted: false
 codec: AAC
 sample_bits: 16
 num_channels: 2
 sampling_frequency: 44100
 language: und

Stream [1] type: Video
 codec_string: avc1.4d401e # 视频的编码器字符串
 time_scale: 3000
 duration: 18500 (6.2 seconds)
 is_encrypted: false
 codec: H264
 width: 640
 height: 480
 pixel_aspect_ratio: 1:1
 trick_play_factor: 0
 nalu_length_size: 4
复制代码

更多请查看官方文档

FFmpeg

FFmpeg 是功能非常强大的视频处理开源软件,很多视频播放器就是使用它来做为内核。后面文章的实例都会使用这个工具。

比如上面将普通 MP4 转换为 FMP4,可以使用如下命令:

ffmpeg -i ./friday.mp4 -movflags empty_moov+frag_keyframe+default_base_moof f.mp4
复制代码

它的命令行格式如下:

ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...
复制代码

它可以有不限数量的输入和输出文件,-i 后面是输入 url,后面不能解析为参数的为输出文件。

 _______              ______________
|       |            |              |
| input |  demuxer   | encoded data |   decoder
| file  | ---------> | packets      | -----+
|_______|            |______________|      |
                                           v
                                       _________
                                      |         |
                                      | decoded |
                                      | frames  |
                                      |_________|
 ________             ______________       |
|        |           |              |      |
| output | <-------- | encoded data | <----+
| file   |   muxer   | packets      |   encoder
|________|           |______________|
复制代码

它将输入文件的容器解开,然后对里面的数据进行解码,然后按照指定的格式进行编码,然后使用指定的容器进行封装生成输出文件。在 decoded frames 后 FFmpeg 可以使用 filter 进行处理,比如添加滤镜、旋转、锐化等操作,filter 分为简单和复杂,复杂可以处理多个输入流。

如果我们只是想改变视频的容器,那么就可以省略解码和编码过程,来提升速度。

ffmpeg -i input.avi -c copy output.mp4
复制代码

-c 是指定编码器,-c copy 表示直接复制编码,-c:v 表示视频编码,-c:a 表示音频编码,比如 -c:v libx264 表示使用 CPU 将视频编码为 h.264-c:v h264_nvenc 则是使用 N卡,这样速度更快。-c:a copy 表示直接复制音频编码。

ffmpeg -y -i myvideo.mp4 -c:v copy -an myvideo_video.mp4
ffmpeg -y -i myvideo.mp4 -c:a copy -vn myvideo_audio.m4a
复制代码

-an 去除音频流 -vn 去除视频流。-y 是不经过确认,输出时直接覆盖同名文件。

ffmpeg -help #查看帮助
ffmpeg -i input.mp4 # 查看视频信息
ffmpeg -formats # 查看支持的容器
ffmpeg -codecs # 查看支持的编码格式
ffmpeg -encoders # 查看内置的编码器
复制代码

更多关于 FFmpeg 请查看官方文档

视频缩略图预览

了解了上面好用的工具,就来用 FFmpeg 来实现一个视频播放器小功能吧。

现在视频网站,当鼠标放到进度条上时就会出现,一个小缩略图来预览这个时间点内容。

ffmpeg -i ./test.webm -vf 'fps=1/10:round=zero:start_time=-9,scale=160x90,tile=5x5' M%d.jpg
复制代码

我们可以通过上面这个命令生成一个雪碧图,由 25 张 160×90 预览图组成。

-vf 参数后面跟着过滤器,多个过滤器用 , 分开,一个过滤器多个参数使用 : 分开。

fps=1/10 表示 10 秒输出一张图,fps=1/60 为一分钟一张,round=zero 时间戳向 0 取整,start_time=-9 是因为 fps 是每多少秒生成一张,并不是从 0 秒开始 -9 是让它从 1 秒开始截取,忽略掉 0 秒的黑屏帧。

scale=160x90 设置输出图像分辨率大小,tile=5x5 将小图用 5×5 的方式组合在一起,M%d.jpg 表示输出为 jpg,而且文件是 M1.jpg M2.jpg... 这样递增。

如果想用 NodeJS,可以用 node-fluent-ffmpeg 的 thumbnails 方法来生成。

有了雪碧图,我们就在上篇文章实现的播放器的基础上在加个视频缩略图功能。主要通过 css 的 background 来实现。

const thumb = document.querySelector('.thumb')
const gapSec = 10 // 一张图片显示几秒
const images = [...] // 图片
const row = 5, col = 5 // 一张图有几行几列
const width = 160, height = 90; // 缩略图的宽高
const thumbQuantityPerImg = col * row

function updateThumbnail(seconds) { // 传入要显示缩略图的秒数
    const thumbNum = (seconds / gapSec) | 0; // 当前是第几张缩略图
    const url = images[(thumbNum / thumbQuantityPerImg) | 0];
    const x = (thumbNum % col) * width; // x 的偏移量
    const y = ~~((thumbNum % thumbQuantityPerImg) / row) * height; // y 的偏移量

    thumb.style.backgroundImage = `url(${url})`;
    thumb.style.backgroundPosition = `-${x}px -${y}px`;
}
复制代码

效果如下

image.png

这里只展示缩略图更新的逻辑,忽略了时间显示,事件处理和样式等代码。

完整的代码请参考 NPlayer

在线演示:nplayer.js.org/

视频切片

有了 MSE 我们就可以将一个视频分割成多个小视频,然后可以自己控制缓存进度来节省流量,还可以将视频压缩成不同的分辨率,在用户网不好的情况动态加载码率低的分段,分成多段还可以实现插入广告,动态切换音频语言等功能。

./audio/
  ├── ./128kbps/
  |     ├── segment0.mp4
  |     ├── segment1.mp4
  |     └── segment2.mp4
  └── ./320kbps/
        ├── segment0.mp4
        ├── segment1.mp4
        └── segment2.mp4
./video/
  ├── ./240p/
  |     ├── segment0.mp4
  |     ├── segment1.mp4
  |     └── segment2.mp4
  └── ./720p/
        ├── segment0.mp4
        ├── segment1.mp4
        └── segment2.mp4
复制代码

当然也可以不切割视频,而使用 HTTP Range 来范围请求数据。

ffmpeg -i ./friday.mp4 -f segment -segment_time 2 -segment_format_options movflags=dash ff%04d.mp4
复制代码

我们使用上面命令将一个视频切成 2 秒的 fmp4 视频片段。

window.MediaSource = window.MediaSource || window.WebKitMediaSource
const video = document.querySelector('video')
const mime = 'video/mp4; codecs="avc1.4d401e, mp4a.40.2"'
const segments = [
    '/static/media/ff0000.5b66d30e.mp4', 
    '/static/media/ff0001.89895c46.mp4', 
    '/static/media/ff0002.44cfe1e4.mp4'
]
const segmentData = []
let currentSegment = 0

if ('MediaSource' in window && MediaSource.isTypeSupported(mime)) {
    const ms = new MediaSource()
    video.src = URL.createObjectURL(ms)
    mediaSource.addEventListener('sourceopen', sourceOpen)
}

function sourceOpen({ target }) {
    URL.revokeObjectURL(video.src)
    target.removeEventListener('sourceopen', sourceOpen)
    const sb = target.addSourceBuffer(mime)
    fetchSegment(ab => sb.appendBuffer(ab))
    sb.addEventListener('updateend', () => {
        if (!sb.updating && segmentData.length ) {
            sb.appendBuffer(segmentData.shift())
        }
    })
    video.addEventListener('timeupdate', function timeupdate() {
        if (
            currentSegment > segments.length &&
            !sb.updating &&
            target.readyState === 'open'
        ) { // 所有片段全部加载完成
            target.endOfStream()
            video.removeEventListener('timeupdate', timeupdate)
        } else if (
            video.currentTime > (currentSegment * 2 * 0.8) 
            // 一个片段时长 2 秒
            // 在一个片段播放到 80% 的时候才去请求下一个片段
        ) {
            fetchSegment(ab => {
                if (sb.updating) {
                    segmentData.push(ab)
                } else {
                    sb.appendBuffer(ab)
                }
            })
        }
    })
    video.addEventListener('canplay', () => {
        video.play()
    })
}

function fetchSegment(cb) {
    fetch(segments[currentSegment])
        .then(response => response.arrayBuffer())
        .then(arrayBuffer => {
            currentSegment += 1
            cb(arrayBuffer)
        })
}
复制代码

这个实例非常简单,并没有处理 seek,自适应码率等复杂功能。

总结

现在视频网站几乎全部都在使用 MSE 来播放视频。使用 MSE 有提供更好的用户体验,更加节约成本等好处。虽然视频播放一般使用 hls dash 等协议的开源客户端来播放视频,我们自己不会使用到 MSE,但这些客户端底层都是使用 MSE,了解 MSE 才更了解这些客户端。

这是弹幕播放器系列文章第二篇,上篇请查看 从零开发弹幕视频播放器1。下篇请查看 原来爱优腾等视频网站都是用这个来播放流媒体的

作者:wopen
链接:https://juejin.cn/post/6953777965838630926

正向代理、反向代理、透明代理

代理:它位于用户客户端和服务端之间,顾名思义它是一个中间商,代替客户端向服务端请求资源,并把服务端响应的资源传递给客户端而不用客户端自己去访问。

根据所处位置的不同分为正向代理、反向代理

一、正向代理:

  正向代理主要是代替客户端请求和接受互联网资源,比如当我们直接访问youtube的时候,你知道结果肯定是要扑街的,这时候可以去找个代理,通过代理我们就能访问了。这时候我们把代理服务看着是客户端。

  正向代理的用途 :

(1)访问本地无法访问的服务器;

(2)缓存作用,加速访问资源;

(3)客户端访问授权,进行上网认证;

(4)代理会记录访问记录,对外可以隐藏访问者的行踪。

 二、反向代理:

   它位于服务端,主要是将用户的web请求分发到后面的真实服务器上(负载均衡),并将真实服务器返回的结果交给用户,此时代理服务器位于服务端,对外就表现为一个服务器。

图2反向代理

反向代理的作用:

(1)保证服务端内部网路的安全,大型网站,通常将反向代理作为公网访问地址,Web服务器是内网。

(2)负载均衡,通过反向代理服务器来优化网站的负载,降低服务器压力。

三、透明代理:

   透明代理的意思是客户端根本不需要知道代理服务器的存在,它改变你的request fields(报文),并会传送真实IP,多用于路由器的NAT转发中。

透明代理也称为强制代理、内联代理或拦截代理。与常规代理相反,透明代理不需要对现有设置进行任何更改。它在浏览互联网时在用户不知情的情况下实施。

透明代理不会操纵请求或更改您的IP。它执行重定向并可用于身份验证。透明代理充当由ISP实现的缓存代理。

透明代理常用于缓存某些高带宽资源。例如,视频将被缓存到代理服务器,当请求查看该视频时,将呈现缓存副本而不向目标服务器发送请求。这是为了有效地使用带宽并缩短响应时间。

组织使用透明代理来限制对特定网站的访问。这用于审查内容。透明代理可以根据特定规则阻止对Internet的访问。此类代理服务器也用于防止DDoS攻击。它可以防止此类冗余请求泛滥并关闭实际的目标服务器。

可以在路由器刷OpenWRT安装shadowsocks使用透明代理+去DNS污染

拥有透明代理的缺点之一是用户控制权被透明代理带走,而用户没有意识到这一点。这是一个隐私问题。其次,透明代理不健壮,容易受到中间人攻击。网络流量可以重新路由到不同的代理。

透明代理的主要问题是可以监控您的所有流量。ISP 可以完全跟踪您的网络跟踪。如果您不希望被监控,第一步是检测您是否使用透明代理。一种常见的方法是在 Chrome 地址栏中输入无效的 URL。未找到网站时来自 Chrome 的典型错误消息与使用透明代理连接时显示的错误消息不同。

如果您正在浏览HTTPS网站,您可以通过单击浏览器上的锁定符号来查看SSL证书信息。当它来自 ISP 时,此证书看起来会有所不同。

Nmap 等命令也用于检测透明代理。

通过PHP脚本自动登录WP

WordPress的密码不记得了怎么办?除了通过邮件找回密码、登录phpmyadmin修改密码以外,还可以通过PHP脚本自动登录Wordpress。比如创建一个autologin.php放到wp根目录下,然后访问这个文件,就自动用指定的用户名登录站点,随后删除该文件即可。

为什么要自动登录WordPress

  • 知道网站管理的用户名以及cpanel信息,不知道密码,也不能修改用户的密码。
  • 本地开发图省事,不想每次都要登录站点。

自动登录Wordpress的PHP脚本

将如下内容写入一个文件,名字叫什么都可以,比如autologin.php,放到网站根目录下。

<?php
require('wp-blog-header.php');
// Automatic login //
$username = "admin";
$user = get_user_by('login', $username );

// Redirect URL //
if ( !is_wp_error( $user ) )
{
    wp_clear_auth_cookie();
    wp_set_current_user ( $user->ID );
    wp_set_auth_cookie  ( $user->ID );

    $redirect_to = user_admin_url();
    wp_safe_redirect( $redirect_to );
    exit();
}

然后打开浏览器,输入该文件地址,例如:

https://www.solagirl.net/autologin.php

这样就能用指定的用户名自动登录WordPress了,在线站点上请勿保留此文件。

让Wordpress时刻保持登录状态

如果要让WordPress不论何时都自动登录,可以用下面的代码,代码写成插件或者放到主题的functions.php里。

function auto_login() {

    if( is_user_logged_in() ){
        return;
    }
    $loginusername = 'admin'; //username of the WordPress user account to impersonate

    // get this username's ID
    $user = get_user_by( 'login', $loginusername );

    if( ! $user ){
        return;
    }

    $user_id = $user->ID;

    // login as this user
    wp_set_current_user( $user_id, $loginusername );
    wp_set_auth_cookie( $user_id );
    do_action( 'wp_login', $loginusername, $user );

    // redirect to home page after logging in
    wp_redirect( home_url() );
    exit;
}

add_action( 'wp', 'auto_login', 1 );

这段代码的作用:只要访问站点,就会自动登录。适合某些特殊用途,比如本地站点测试不想重复登录。

国家-防火墙实现原理

不同ISP建立的不同骨干网之间也有数据交换中心,使得信息和数据包可以自由的从全国任何地方流向其他地方。
而数据包在庞大的“网上公路”迷路的可能性。在各个级别的网路(局域网->域域网->广域网)中,分布着无数路由节点,每一张骨干网都有自己负责的路由群组和节点,整个群组统称为as自治系统(Autonomous system)

每一个骨干网管理的as自治系统都经过名为互联网号码分配局的国际机构分配唯一识别代码,例如,中国电信163骨干网的as自治系统编号为AS4134。每一张骨干网都有内部路由协议,每一个节点都在依据某种规定互相交换他们所连通的ip地址信息,作为数据包在“旅行”过程中的指路人。而全国性的骨干网之间也依靠外部路由协议互相交换它们所掌握的“服务器地图“,典型的有BGP协议。

边界网关协议(BGP)是运行于 TCP 上的一种自治系统的路由协议。 BGP 是唯一一个用来处理像因特网大小的网络的协议,也是唯一能够妥善处理好不相关路由域间的多路连接的协议。 BGP 构建在 EGP 的经验之上。 BGP 系统的主要功能是和其他的 BGP 系统交换网络可达信息。网络可达信息包括列出的自治系统(AS)的信息。这些信息有效地构造了 AS 互联的拓扑图并由此清除了路由环路,同时在 AS 级别上可实施策略决策。

国家-防火墙原理

1.基于UDP协议的域名解析服务劫持/DNS缓存污染
GFW会对所有经过骨干出口路由的基于UDP的DNS域名查询请求进行Intrusion Detection Systems(入侵检测系统)检测,一旦发现处于黑名单关键词中相匹配的域名查询请求,防火长城作为中间设备会向查询者返回虚假结果。
也就是说浏览器无法查询到域名对应的正确IP,也就无法对其进行访问,数据包会传输到虚假的IP,从而没有响应。

2.IP地址或传输层端口人工封锁——BGP路由劫持/“路由黑洞”
GFW的重要工作方式之一是在网络层的针对IP的封锁。事实上,GFW采用的是一种比传统的访问控制列表(Access Control List,ACL)高效得多的控制访问方式——路由扩散技术。分析这种新的技术之前先看看传统的技术,并介绍几个概念。

访问控制列表(ACL)

ACL可以工作在网络的二层(链路层)或是三层(网络层),以工作在三层的ACL为例,基本原理如下:想在某个路由器上用ACL控制(比如说是切断)对某个IP地址的访问,那么只要把这个IP地址通过配置加入到ACL中,并且针对这个IP地址规定一个控制动作,比如说最简单的丢弃。当有报文经过这个路由器的时候,在转发报文之前首先对ACL进行匹配,若这个报文的目的IP地址存在于ACL中,那么根据之前ACL中针对该IP地址定义的控制动作进行操作,比如丢弃掉这个报文。这样通过ACL就可以切断对于这个IP的访问。ACL同样也可以针对报文的源地址进行控制。如果ACL工作在二层的话,那么ACL控制的对象就从三层的IP地址变成二层的MAC地址。从ACL的工作原理可以看出来,ACL是在正常报文转发的流程中插入了一个匹配ACL的操作,这肯定会影响到报文转发的效率,如果需要控制的IP地址比较多,则ACL列表会更长,匹配ACL的时间也更长,那么报文的转发效率会更低,这对于一些骨干路由器来讲是不可忍受的。

路由协议与路由重分发

而GFW的网络管控方法是利用了OSPF等路由协议的路由重分发redistribution)功能,可以说是“歪用”了这个本来是正常的功能。

动态路由协议

说路由重分发之前先简单介绍下动态路由协议。正常情况下路由器上各种路由协议如OSPF、IS-IS、BGP等,各自计算并维护自己的路由表,所有的协议生成的路由条目最终汇总到一个路由管理模块。对于某一个目的IP地址,各种路由协议都可以计算出一条路由。但是具体报文转发的时候使用哪个协议计算出来的路由,则由路由管理模块根据一定的算法和原则进行选择,最终选择出来一条路由,作为实际使用的路由条目。

静态路由

相对于由动态路由协议计算出来的动态路由条目,还有一种路由不是由路由协议计算出来的,而是由管理员手工配置下去的,这就是所谓的静态路由。这种路由条目优先级最高,存在静态路由的情况下路由管理模块会优先选择静态路由,而不是路由协议计算出来的动态路由。

路由重分发

刚才说到正常情况下各个路由协议是只维护自己的路由。但是在某些情况下比如有两个AS(自治系统),AS内使用的都是OSPF协议,而AS之间的OSPF不能互通,那么两个AS之间的路由也就无法互通。为了让两个AS之间互通,那么要在两个AS之间运行一个域间路由协议BGP,通过配置,使得两个AS内由OSPF计算出来的路由,能通过BGP在两者之间重分发。BGP会把两个AS内部的路由互相通告给对方AS,两个AS就实现了路由互通。这种情况就是通过BGP协议重分发OSPF协议的路由条目。

另外一种情况,管理员在某个路由器上配置了一条静态路由,但是这条静态路由只能在这台路由器上起作用。如果也想让它在其他的路由器上起作用,最笨的办法是在每个路由器上都手动配置一条静态路由,这很麻烦。更好的方式是让OSPF或是IS-IS等动态路由协议来重分发这条静态路由,这样通过动态路由协议就把这条静态路由重分发到了其他路由器上,省去了逐个路由器手工配置的麻烦。

GFW路由扩散技术的工作原理

前面说了是“歪用”,正常的情况下静态路由是由管理员根据网络拓扑或是基于其他目的而给出的一条路由,这条路由最起码要是正确的,可以引导路由器把报文转发到正确的目的地。而GFW的路由扩散技术中使用的静态路由其实是一条错误的路由,而且是有意配置错误的。其目的就是为了把本来是发往某个IP地址的报文统统引导到一个“黑洞服务器”上,而不是把它们转发到正确目的地。这个黑洞服务器上可以什么也不做,这样报文就被无声无息地丢掉了。更多地,可以在服务器上对这些报文进行分析和统计,获取更多的信息,甚至可以做一个虚假的回应。

有了这种新的方法,以前配置在ACL里的每条IP地址就可以转换成一条故意配置错误的静态路由信息。这条静态路由信息会把相应的IP报文引导到黑洞服务器上,通过动态路由协议的路由重分发功能,这些错误的路由信息可以发布到整个网络。这样对于路由器来讲现在只是在根据这条路由条目做一个常规报文转发动作,无需再进行ACL匹配,与以前的老方法相比,大大提高了报文的转发效率。而路由器的这个常规转发动作,却是把报文转发到了黑洞路由器上,这样既提高了效率,又达到了控制报文之目的,手段更为高明。

这种技术在正常的网络运营当中是不会采用的,错误的路由信息会扰乱网络。正常的网络运营和管控体系的需求差别很大,管控体系需要屏蔽的IP地址会越来越多。正常的网络运营中的ACL条目一般是固定的,变动不大、数量少,不会对转发造成太大的影响。而这种技术直接频繁修改骨干路由表,一旦出现问题,将会造成骨干网络故障。

所以说GFW是歪用了路由扩散技术,正常情况下没有那个运营商会把一条错误的路由信息到处扩散,这完全是歪脑筋。或者相对于正常的网络运营来说,GFW对路由扩散技术的应用是一种小聪明的做法。正常的路由协议功能被滥用至此,而且非常之实用与高效,兲朝在这方面真是人才济济。

3.TCP RST重置
旁路监听的方式一般是将主交换机的数据镜像到控制系统,控制系统可以采用libpcap捕获数据包。在这种情况下要阻断tcp连接的建立只要在监听到第一次握手的时候,控制系统伪造服务器发起第二次握手回应,就能阻断客户端与服务器连接的建立。因为我们的系统在内网,发出的报文肯定比服务器快,这样客户端接收到我们伪造的报文以后会回应第三次握手,当服务器真正的报文到达的时候客户端将不再处理,此时客户端再向服务器请求数据,因为seq号和ack号出错,服务器不会受理客户端的请求。

4.协议检测→根据流量协议拆包→关键词匹配→封锁
HTTP协议有非常明显的特征,可以轻易被GFW系统检测和识别,GFW进而依据HTTP协议规则对数据包进行拆解,由于其表现为明文,所以可以直接进行关键词匹配。例如,从HTTP的GET请求中取得请求的URL。然后GFW拿到这个请求的URL去与关键字做匹配,比如查找Twitter是否在请求的URL中。而关键字匹配使用的依旧是一些高效的正则表达式算。

5.深度包检测(机器学习识别翻墙流量→直接阻断)
对于混淆流量和非传统加密协议,GFW正在使用大家耳熟能详的“人工智能”技术,将这些各种各样难以判断和识别的翻墙流量与正规的政企跨境流量相区分开来。

以上为网友分析,非专业资料

光纤通信网络安全

目前,光纤窃听的方法主要包括光纤弯曲法、V 型槽切口法、散射法、光束分离法、渐近耦合法等

1、直接切断光缆,接入光耦合器,(光分束器),使目标信号分为两个完全相同的信号

2、光纤弯曲在5至10MM可正确导光,用夹式耦合器不破坏光纤就可,

3、V 型槽切口法是通过一个接近纤心的V 型槽导出光纤信号进行窃听的方法。它要求V 型槽的切面与光纤信号传输方向之间的夹角大于完全反射的临界角。当达到这个条件后,在保护层中传输的部分信号和在V 型槽切面发生迭加效应的信号发生完全反射,导致信号通过光纤边界泄露。

  由于这种窃听方法导致的信号衰减很小,因此很难被发现。V 型槽切口法需要精确的切割和切面抛光设备,窃听部署需要持续较长时间,因此,光纤保护层的切割和抛光过程将面临被发现的危险。

4、散射法是采用光纤Bragg 光栅技术实现的一种隐蔽窃听方法,它采用一个紫外光激态激光器产生紫外光的迭加并影响目标光纤信号,通过在目标光纤纤心形成的Bragg 光栅反射出的一部分光信号实现对目标光纤的隐蔽窃听,是目前最先进的光纤窃听技术,常规的网络检测和监控手段都很难识别这种窃听行为。散射法不需要对光纤进行弯曲、切割或抛光,但是它需要更精密的窃听设备并且部署非常困难,比如产生有效的外部干扰干涉光束,并在目标光纤纤心产生光栅耀斑都需要精密的控制技术,而对于光栅耀斑反射出的光信号的检测也需要精密的检测技术。

5、渐近耦合法,渐近耦合法首先抛光光纤的保护层,使窃听光纤纤心尽可能贴近目标光纤纤心,通过减少保护层的反射引出部分信号到窃听光纤里面,由于光纤纤心非常细,实施这种方法非常困难,又由于光纤的保护层被抛光将产生1~2 dB 的光纤损耗,因此很难实现隐蔽的窃听。

  以上几种窃听光纤信号的方法都可以通过一些技术手段得到光纤信号,特别是光纤弯曲法、V 型槽切口法,能够实现隐蔽窃听,又由于实施相关窃听相对容易一些,因此具有较高的实战应用价值。

如何检测是否有窃听:

用光测试仪测试光衰,用光时域反射仪来看光纤中的断点,变形等。

光时域反射仪(OTDR)

  OTDR 的原理是通过精确地发射各种波长的有规律的光脉冲并测量反射光信号返回的时间和反射光信号的强度来分析光纤信道情况。通过跟踪反射光信号的时间和强度,OTDR 能够确定光环路的完整路径。另外,OTDR还可以识别光纤断路的距离。通过测试和保存OTDR 的参数,终端用户可以监控光路的变化并识别任何可能的光路入侵。由于OTDR( 包括偏振OTDR) 能够识别不连续的损耗,可以检测双折射、压力和其他由窃听引起的光信号变形等,因此,具有检测光纤断裂、弯曲、异常损耗和各种窃听等异常情况的能力。

另外可以从技术上防止光纤被窃听而造成的敏感信息泄露。比如加密,目前,比较实用的光纤信号保护手段主要有无规律载波光纤通信技术、基于混沌保密的光纤通信方式和光纤信道加密技术等。使用这些技术,可以在一定程度上增强光纤信号的保密性,这种信息保护方式对于业余窃听爱好者来说可能是一筹莫展,但是它对具有超强计算和分析能力的专业窃听机构并不能提供完全的保密性。

阿里云打开mysql远程连接

先进阿里云控制台,安全组规则打开请允许入方向的3306端口TCP连接

然后再进操作系统

解决mysql不能使用IP链接的问题

1) 修改%xampp%\mysql\bin\my.ini文件,搜索

bind-address=“127.0.0.1”

改成

bind-address=“0.0.0.0”

2) 修改%xampp%\phpMyAdmin\config.inc.php文件,搜索:

/* Authentication type and info */

$cfg[‘Servers’][$i][‘auth_type’] =‘config’;

$cfg[‘Servers’][$i][‘user’] =‘root’;

$cfg[‘Servers’][$i][‘password’] =”;

$cfg[‘Servers’][$i][‘extension’] =‘mysql’;

$cfg[‘Servers’][$i][‘AllowNoPassword’] = true;

改成:

/* Authentication type and info */

$cfg[‘Servers’][$i][‘auth_type’] =‘cookie’;

$cfg[‘Servers’][$i][‘user’] =‘root’;

$cfg[‘Servers’][$i][‘password’] =‘root’;

$cfg[‘Servers’][$i][‘extension’] =‘mysql’;

$cfg[‘Servers’][$i][‘AllowNoPassword’] = true;

3) 启动mysql、apache,登录phpMyAdmin。在“权限”部分添加一个root@%用户,内容参照 root@localhost 的设置;两者的区别就是主机字段,一个写%,一个写localhost;

xampp下mysql开启远端连接

1、进入phpmyadmin管理界面首页,点击“权限”后,再“添加新用户”,用户名:root(随意),主机:%(必须是%),对应的密码可以设置可以不设置,即可开通远程连接;2、或者用工具Navicat链接到本地数据,点击“管理用户”,后添加用户,同上操作即可开通远端连接。

NAT类型

下载并运行《NatTypeTester》,因工具原地址已失效,将STUN server栏中的地址修改成“stun.voipbuster.com”或者stun.qq.com,点击“GET”即可测试类型。

1. Full Cone NAT:NAT1将来自同一个内部元组X的的所有请求转换为同一个外部元组Y,无论这些请求属于同一个应用程序还是多个应用程序。此外,当X-Y转换关系建立后,任何外部主机都可以随时使用Y中的地址和端口作为目标地址和端口,向内部主机发送UDP消息。因为对外部请求的来源没有限制,所以这个方法足够简单,但是不那么安全。(任何外部主机/端口都可以与前一个内部节点映射到的外部元组通信)


2.Restricted Cone NAT:它是Full Cone的受限版本:来自同一个内部元组X的的所有请求都被NAT转换为同一个外部元组Y,与Full
Cone相同,但不同的是只有当内部主机已经向外部主机发送了消息(假设其IP地址为Z)时,
外部主机可以以Y中的信息作为目标地址和端口向内部主机发送UDP请求消息,这意味着NAT设备只转发(转换目标地址/端口)那些来自当前已知外部主机的UDP消息,从而保证了外部请求源的安全性。
(IP相同,端口任意,可以与前一个内部节点映射到的外部Tuple通信)

Port Restricted Cone NAT(NAT3

端口受限锥型NAT,相比NAT2,NAT3 又增加了端口限制,也就是说IP、端口都会受限。


Symmetric NAT(NAT4

对称型NAT,具有端口受限锥型的受限特性,内部地址每一次请求一个特定的外部地址,都可能会绑定到一个新的端口号。也就是请求不同的外部地址映射的端口号是可能不同的。这种类型基本上就告别 P2P 了。


由上面可以看出从NAT1到NAT4限制越来越多,为了各种需求,我们希望提升NAT类型。提升NAT类型的好处有,浏览网页、观看视频、游戏等更顺畅,下载速度更稳定快速,尤其是对喜欢玩游戏的用户,提升NAT类型后更容易进入游戏房间连线等。