整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

聊聊视频会议系统中web端与客户端通信的关键技术设计

聊聊视频会议系统中web端与客户端通信的关键技术设计(1)

.引言

本篇文章也涉及到很多知识点,如果对于细节部分不是很了解,可以阅读前面的文章,能够帮助你更加理解本篇文章。通过系列文章来讲解,本篇文章是第一篇。参考文章内容列表如下:

SRS流媒体框架分析(1)

SRS流媒体之RTMP拉流框架分析(4)

SRS流媒体之RTMP拉流框架分析(3)

SRS流媒体之RTMP推流框架分析(2)

简述SRS流媒体服务器相关技术

SRS流媒体服务器集群之Forward模式(2)

SRS流媒体服务器集群之Forward模式(1)

SRS流媒体服务器之HLS源码分析(2)

SRS流媒体服务器之HLS源码分析(4)

SRS流媒体服务器之RTMP协议分析(2)

SRS流媒体服务器之HLS源码分析(3)

SRS流媒体服务器之HLS配置、测试和技术选型

SRS流媒体服务器之HLS源码分析(1)

SRS流媒体服务器之RTMP协议分析(1)

SRS流媒体服务器之RTMP推流消息处理(1)

SRS流媒体服务器之HTTP-FLV框架分析(1)

SRS流媒体服务器集群之Edge模式(1)

SRS流媒体服务器集群之Edge模式(2)

SRS流媒体服务器之HTTP-FLV框架分析(2)

SRS流媒体服务器集群之Edge模式(3)

SRS流媒体服务器之HTTP-FLV框架分析(2)

手把手配置HLS流媒体服务器

详解Nginx系列

Nginx架构与Handler模块最详分析(2)

Nginx架构与Handler模块最详分析(3)

Nginx架构与Handler模块最详分析(1)

Nginx 源码分析之 Filter 模块(1)

Nginx 源码分析之 Upstream 模块(1)

流媒体推拉流实战之RTMP协议分析(BAT面试官推荐)

超详细RTMP协议详解(资深流媒体架构师推荐)

RTP协议

RTP之AAC框架分析

详解RTP打包AAC实战分析(1)

详解RTP封包和拆包AAC实战分析(2)

详解RTP打包AAC实战分析(1)

详解RTP协议之H264封包细节(1)

详解RTP协议之H264封包和解包实战

详解RTCP协议和源码分析

1.视频会议系统行业简述

视频会议系统(Video Conference)是指通过因特网实现位于多个(至少两个)地点的人们进行类似于面对面交流的远程视音频通信服务平台。视频会议系统除了支持传统的文字聊天和语音通话功能,还集成了动态图像、电子白板、群组交流和视频通话等强大功能。它最大化地丰富了人们在生活和工作中交流的方式,也有助于提高人们沟通和交流的质量。

视频会议系统,已经广泛地应用于政府部门、军队和大型企事业单位,还扩展到能源、科技、医疗、金融以及教育等领域。近些年来,随着视频会议应用从传统行业、大型公司转向中小型企业、普通用户和个人,视频会议系统在国内的市场规模得到不断地发展壮大。近六年,我国视频会议系统市场销售份额(来自《2016-2022 年中国视频会议系统市场分析报告》),如下所示:


2.Nginx 服务器简述

Nginx(engine X)是一款轻量级的 Web 服务器/反向代理服务器及电子邮件代理服务器。随着 HTTP 核心模块和各类 HTTP 扩展模块的出现,Nginx 被更多的国内公司用来取代 Apache 而独立承担起 Web 服务器,如淘宝、百度、新浪、网易以及腾讯等。由于 Nginx 本着“一切皆为模块”的设计理念,活跃的社区出现了大量的第三方扩展模块,这也让 Nginx 功能越来越强大。例如,Arut 开发的 nginx-rtmp-module 模块可以支持 RTMP 协议,使 Nginx 成为支持直播和点播服务的流媒体服务器。在这里我也推荐一款国内开源的流媒体服务器,SRS,这个支持的组件更多,功能也更好用。

W3C 联合全球 60 多家公司,历时八载,于 2014 年 8 月发布了 HTML5 正式标准。HTML5 标准提出了大量新特性,特别是 Web Socket 协议,一种支持服务器主动推送消息给客户端,非常适合构建网络直播、在线教育以及视频会议等实时 web 应用。目前,一种新型的 HTML5 视频会议客户端成为研究热点,主要包括以下三种:基于 HLS 的HTML5 客户端、基于 Web RTC 的 HTML5 视视客户端(在各大主流流媒体厂商得到了广泛应用)和基于 Web Socket 协议、HTML5原生组件及 Java Script 的 HTML5 客户端。

视频会议系统可划分为硬件视频会系统和软件视频会议系统。大多数硬件视频会议系统的厂商都是国外公司,如美国宝利通(Polycom)、挪威泰德集团(TANDBERG)以及日本索尼(sony)等,当然他们也推出对应地软件型视频会议系统。国内提供视频会议系统服务的公司,主要包括华为、科达、中兴以及瑞福特,腾讯,钉钉,声网等,一般只提供软件型视频会议系统。


3.协议介绍与关键技术讲解

3.1TCP

TCP(Transmission Control Protocol,传输控制协议)是互联网传输层最重要的协议之一,提供端到端服务的协议。TCP 是一种面向连接的可靠传输协议,提供一种全双工的通信。如下图所示:


传输层还有一种非常重要的协议 UDP(User Data Protocol,用户数据报协议),是一种非连接的尽最大努力交付的协议。UDP 和 TCP 设计机制非常不同,甚至是相对的。为了明确 TCP 的特点,下面将 TCP 和 UDP 进行比较。如下图所示:


TCP 和 UDP 进行比较

TCP 最大的优点就是数据传输可靠。经过三次握手机制建立连接,TCP 按顺序发送数据包,接收方需要向发送方确认数据包的信息。因此,TCP 不仅保证了数据正确性,还保证了数据顺序性。目前,基于 TCP 的应用十分广泛,如 HTTP、FTP、SMTP、IMAP、POP3 以及 TELNET都是基于TCP。


3.2 RTP和RTCP

RTP(Real-time Transport Protocol,实时传输协议)和 RTCP(Real-time TransportControl Protocol,实时传输控制协议)是一对姊妹协议,由 IETF(The InternetEngineering Task Force )于 1996 年 1 月公布 RFC1889(现已更新至 RFC3550)文档所发布。RTP 主要用于互联网上音频、图像及视频等多媒体实时端到端传输服务RTCP用于保障 RTP 传输的服务质量交换控制信息。

RTP 报文(RTP 协议的报文)由头部(RTP Header)和数据负载(Payload)组成。其中,RTP 报文的头部结构,如下图所示:


RTP 报文的头部结构

RTP Header 长度是可变的,固定长度为前 12 字节,可选 CSRC 标识列表仅出现在混合器插入情况。关于 RTP Header 说明,如下:

(1)V:2 位,标识 RTP 协议版本号,当前协议版本号为 2。

(2)P:1 位,填充标志位,如果 P=1,RTP 报文的尾部使用一个或多个字节 0 来填充。

(3)X:1 位,扩展标志位。如果 X=1,表示 RTP 报头后跟有一个扩展包头字段。

(4)CC: 4 位 CSRC 计数器(CSRC count)。标识可选字段CSRC 标识符的个数。

(5)M: 1 位 标记位。不同的有效载荷意义不同,可参见spec文档。

(6)PT: 7 位 有效载荷类型。说明 RTP 报文载荷的类型,如ACC 音频、MPEG 视频,便于客户端解析。

(7)Timestamp: 4 字节 时间戳。记录了 RTP 报文的数据负载的第一个字节(8bits)的采样时间。接收者使用该值计算延迟(延迟抖动),进而控制同步。

(8)SSRC identifier: 4 字节 同步信源标识符。该字段随机选择的,但是两个同步信源在一个视频会议中不能取相同SSRC 值。

(9)CSRC identifier: 4 字节 特约信源标识符。CSRC 标识由混合器插入,可以有 0-15 个,个数为 CC 字段值。

RTCP 实时传输控制协议,用于弥补 RTP 不保证服务质量的不足。RTCP 为 RTP 提供服务质量检测控制与反馈、实时流间的同步以及多播中成员的标识。当应用程序开启 RTP 会话时,RTP 使用偶数端口RTCP 则使用相邻奇数端口。也就是说RTP和RTCP使用的是不同的socket通道。在 RTP 会话中,每个参与者周期性地发送 RTCP 报文,包含已发送(接收)数据包、丢失数据包等统计信息接收端获取这些统计信息,就可以及时调整发送速率,甚至调整数据负载的类型。正如前面文章所描述的,RTCP 数据报主要类型SR(Sender Report,发送端报告)、RR(Receiver Report,接收者报告)、SDES(SourceDescription Items,源描述)、BYE(Goodbye,通知离开)以及 APP(Application-defined,自定义应用)。RTCP具体的头部和相关协议文档,可以阅读前面的文章。

本次举例,使用视频会议系统,是使用RTP/RTCP基于TCP进行传输。


3.3 RTMP

RTMP(Real Time Messaging Protocol,实时消息传输协议)是一种用来进行视音频等实时数据传输协议。RTMP 是一种私有协议,由 Adobe Systems 开发专用于 Flash 客户端和流媒体服务器之间实时通信。RTMP 基于传输层 TCP 之上,默认端口为 1935。目前,支持 RTMP 协议的服务器有很多,如 Adobe Media Server/Red5/ Nginx/SRS。RTMP协议已经广泛应用于实时直播、点播(VOD)以及视频通信系统。

3.3.1 RTMP数据包

RTMP 不仅传输音视频数据,需要传输信令交互数据,这些数据叫作 Message。为了接收端区分 Message,发送端必须给其加上 Header 信息,即 Message Header。Message Header 结构,如下图所示:

Message Header 结构

(1)Message Header 总共包括四个字段,字段说明如下:

(2)Message Type ID: 1 字节 消息类型。1-7 用于协议控制8 用于音频数据,9 用于视频数据,15-20 用于 AMF 命令。

(3)Message Length: 3字节消息长度。表示消息中数据负载的长度大小。

(4)Time Stamp: 4字节时间戳。采用绝对时间

(5)Stream ID: 3字节媒体流 ID。标识消息所属媒体流ID

对表中 Message Type ID 解释如下:RTMP 总共定义了十多种消息类型(具体可以参考spec文档),每一种类型具有指定的 ID。下面重点说明三种消息类型:

(6)Message Type ID 为 4 表示 UCM(User Control Messages,用户控制消息),如 StreamBegin、Stream End

(7)Message Type ID 为 18 表示 AMF0 元数据消息。AMF(Action Message Format,动态信息格式)数据是一种与 Flash服务器高效交互的二进制编码数据,如 00 表示 Double02 表示 StringAMF 数据包括 AMF0、AMF3

(8)Message Type ID 为 20 表示 RPC(Remote Procedure Call,远程过程调用)命令消息,主要分为 Net Connection 和 Net Stream 两大类型。前者包括 connect、call、closecreate Stream 命令;后者包括 play、publish、seek 与 pause 命令。

Message 很可能非常大,比如视频数据,由于网络 IP 层传输数据长度有限(以太网规定 MTU 为 1500 字节),Message 往往需要分片。RTMP 将分片得到的小的数据包叫作 Chunk又称“RTMP 数据包”为了标识每个 Chunk,我们也需要给其添加头部信息,即 Chunk Header。RTMP 数据包如下图所示:

RTMP 数据包

Chunk Header 包括三部分标识本 Chunk 的 Chunk Basic Header,标识本 Chunk 所属 Message 的 Chunk Message Header,可扩展的 Extended Timestamp。

(9)Chunk Basic Header(1 字节):由 Header Type 与 Channel ID 组成。Header Type 占2bit,决定头部长度,00-11 分别与 12、8、4、1byte(s)相对应。Channel ID 用于标识通道类型,如下所示:

02: Ping 和 Byte Read 通道

03: Invoke 通道

04: Audio 和 Vidio 通道

05 06 07 :服务器保留

(10)Chunk Message Header(可变长度):之前说过 Message Header 长度为 11bytes,包含 4 个字段。Chunk Message Header 重新排列了这 4 个字段:Time Stamp、MessageLength、Message Type ID、Stream ID。当 Message 分片为 同属于一个Message的Chunk 时候,会依次压缩掉相同的字段(Message Length、Message Type ID 组合在一起),分别得到 11、7、3、0byte(s)情况。具体的解释,可以看看前面的文章,详解RTMP。

(11)Extended Timestamp(4 字节):只有时间戳溢出时才出现的该字段,一般可忽略该字段部分。

因此,Message 是 RTMP 视音频流传输的逻辑方式,Chunk是RTMP 视音频流传输的实际方式。用户发送的数据流成为 Message 有效载荷(Message Body),被分割成固定大小的 Chunk,接着传给下层 TCP 发送出去。


3.3.2 RTMP交互

RTMP 将数据按类型分割成一个个固定长度的数据包(Chunk)。视频数据包默认包体大小是 128bytes音频包体默认大小是 64bytes。对于传输音频/视频数据,RTMP协议既可以采用非常流行的 FLV 封装格式封装数据(视频为 H264 格式,音频为 AAC 格式),又可以采用默认的由 Adobe 公司开发的 AMF格式

在传输 RTMP 数据包之前,必须通过 RTMP 握手机制建立 RTMP 连接。连接建立成功之后,我们可以基于 RTMP 连接按照指定格式传输视音频数据。这些过程,构成了RTMP 交互过程,整个交互的过程在前面的文章也有通过wireshark抓包分析过,可以参考。

(1)握手过程。

RTMP 连接从握手开始,规范规定握手使用三组固定大小的块组成。发起 RTMP 连接的一方(客户端)发送的块记作 c0,c1 和 c2,接收连接的另一方(服务器)发送的块记作 s0,s1 和 s2。客户端首先发送 c0 和 c1 块;客户端必须在接收到 s1 后才能发送 c2;客户端发送任何 RTMP 包数据必须等收到 s2 之后

服务器端在接收 c0 之后,才可以发送 s0 和 s1;服务器必须在接收到 c1 之后才能发送 s2;服务器发送任何 RTMP 包数据必须等到收到 c2 之后。以上的规定就是 RTMP 握手协议内容,通过该协议客户端就和服务器之间建立了 RTMP 连接,RTMP链接一般是4次握手,进而可以相互传输数据。

(2)建立连接。经过握手机制之后,客户端与服务器可以互相发送 RTMP 数据包。RTMP协议规定,传输与播放媒体流需要先建立网络连接Net Connection)事件,也就是connect 过程。客户端先发送 connect 事件到服务器,如果服务器拥有足够资源进行处理就会立即返回连接正确响应,这样一个网络连接就成功建立了。

(3)建立网络流。客户端发送 create Stream 协议包给 RTMP 服务器,申请建立网络流(Net Stream)。通道与网络流(Net Stream)息息相关。RTMP 协议提供了 Ping、Invoke、Audio 和 Video 等通道用于传输不同类型的数据。单个网络连接上使用交错复用技术(在实际抓包分析时,也不一定就是一个视频包,然后一个音频包,可能是先发一组视频包,然后再发送音频包,这样做的原因分析,在前面的文章也有分析过),可将不同类型的数据包同时通过不同通道传输。可见,一个网络连接可包括多条通道,即多条通道并存于一个连接中。RTMP 协议是根据数据类型和用途,从连接中建立网络流并作为通道传输相应数据流。

(4)数据传输。对于播放play、删除流delete、发布publish、暂停pause、停止stop、重新商定 chunk 大小等数据流处理,RTMP 协议也规定了相应的命令。例如拉流播放,当客户端发送 play 命令后,RTMP 服务器会在建立的网络流中向客户端返回音视频流,进而客户端播放器接收并解码数据流就可以进行播放。

(5)Close 过程。服务器在发送完所有音视频数据之后或客户端异常退出,需要释放网络流、网络连接等资源,从而最终关闭 RTMP 协议通信过程。


RTMP握手和发送数据的过程为,握手、建立连接、创建流,数据传输,结束组成。完整的过程如下图:


RTMP RTMP交互过程

注意:在RTMP握手之前,TCP的三次握手已经成功的建立了连接。


4.Web Socket

Web Socket 协议是 HTML5 中一种全新的持久化协议,支持服务器主动推送消息给客户端,即浏览器只需发送一次请求就可源源不断地获取服务器端的数据。Websocket提供基于 TCP 的双向通道,特别适合构建实时 web 应用。

HTTP 及其改进 Polling 和 Long Poll 技术,也能模拟出实时 Web 应用,但存在带宽消耗大、CPU 资源占用多以及延迟大等缺点。Web Socket 协议可以成功地解决这些难题,该协议具有以下特点。

(1)持久化。Web Socket 连接从建立之后,除非客户端或服务器主动断开连接,否则就会一直存在。

(2)双向性。Web Socket 可看作基于 TCP 的socket(浏览器暂不支持 socket),提供全双工通信。当使用 Web Socket 协议时,服务器可以主动推送消息给浏览器,实现真正的实时通信。

Web Socket 协议主要包含两部分:Web Socket 握手和 Web Socket 数据帧。当我们使用 Web Socket 协议传输数据时,客户端必须先按照 Web Socket 的握手机制与服务器建立连接。握手成功便建立 Web Socket 连接,客户端与服务器间就可以按照 Web Socket 数据帧格式双向传输数据

Web Socket 协议存在 6.5、10、13 等多个草案,导致其具有多个版本的握手协议。各个版本间存在较大差异。差异如下图:


如果是基于SHA-1 的方式的 Web Socket 握手机制。草案文档 RFC6455。为了简单化以及兼容 HTTP 程序,Web Socket 协议采用了 HTTP 的握手形式,并对其进行了修改。握手机制,包括以下三个步骤:

(3)客户端向服务器发送特殊的 GET 请求。除了包括正常的 HTTP 头部,Web Socket握手请求头部还会添加 Upgrade、Connection 以及 Sec-Web Socket-Key 等字段。前两个字段表示 HTTP 升级到 Web SocketSec-Web Socket-Key 用于安全校验

(4)服务器返回 Web Socket 握手应答。服务器返回“101 Switching Protocols”状态行与 Upgrade、Connection 以及 Sec-Web Socket-Accept 响应头部信息。

Sec-Web Socket-Accept 计算过程:服务器取出 Sec-Web Socket-Key 字段,然后与全局唯一标识(GUID)“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”字串进行拼接并做 SHA-1 计算,接着对得到 SHA-1 结果进行一次 base64 加密

(5)浏览器验证收到的握手应答。基于 Sec-Web Socket-Key,客户端采用同样的计算方式,获得 Sec-Web Socket-Accept。如果客户端计算值与服务器返回对应字段值一致,握手成功。

通过握手,客户端与服务器便建立了 Web Socket 连接。接着,二者就可以基于Web Socket 数据帧格式进行相互通信。Web Socket 数据帧的结构,如下图所示:


Web Socket 数据帧

由于负载的长度可变,Web Socket 数据帧头部的长度也是可变的。Web Socket 数据帧头部基本部分,字段解释如下:

(6)FIN:1bit:标记帧是否结束。

(7)RSV1-3:RSV1,RSV2,RSV3扩展位各1bit,一般都为0。

(8)OPCODE:表示负载类型,只定义为0x0-0x A,用4bit表示,不同类型如下:


OPCODE 类型

(9)MASK:掩码处理标记,1bit表示,如果是1,Payload Data 需要经过掩码处理。

(10)Extended payload Length :负载长度,是可变的,大小是7bits、23bits、71bits。

当 Web Socket 数据帧 Payload 在 0-125 字节之间,Payload length 占 7bits;当 Web Socket数据帧Payload 在 126-65535 字节之间,Payload length 占 7+16bits,其中前 7bits 值为 126,后 16bits 表示帧 Payload 长度;当 Web Socket 数据帧 Payload 超过 65535 字节,Payloadlength 占 7+64bits,其中前 7bits 值为 127,后 64bits 表示帧 Payload 长度。长度表示遵循一个原则,用最少的字节表示帧长度 payload,这种设计思想,在有些协议中也能体现出来

注意:Web Socket 数据帧还可以分片,详细可以参考RFC6455文档。


4.1 Web Socket API

Web Socket API是 HTML5 为浏览器操作 Web Socket 所提供的一组方法。首先,有必要了解浏览器对 Web Socket 的支持情况,如下图所示:

火狐(Firefox):大于等于4.0版本才支持。

谷歌(Chrome):大于等于4.0版本才支持。

IE 浏览器(Internet Explorer):大于等于9.0版本才支持。

Opera:大于等于10.0版本才支持。

Safari:大于等于5.0版本才支持。


由此可见,主流的浏览器都已经支持 Web Socket 功能。HTML5 为 Web 开发人员提供非常简单的 Web Socket API。以’ws’或’wss’开头形式的成员 URL,表示 Web Socket 服务器的地址,作为客户端 new一个 Web Socket 对象的参数。Web Socket 帧包括三种状态 CONNECTION、OPEN 以及CLOSED;还包括 TEXT_FRAME、BINARY_FRAME、PING_FRAME、PONG_FRAME以及 CLOSING_FRAME9 种帧类型。

(1)Send()方法用于向 Web Socket 服务器发送数据。

(2)Close()方法可以关闭连接。

Web Socket API 还提供三个重要的事件方法:onopen()、onmessage()以及 onerror()。三个方法的解释如下:

(3)onopen():客户端创建的 Web Socket 对象与服务器握手成功后,触发该事件。表示客户端成功建立 Web Socket 连接。

(4)onmessage():服务器端发送的数据到达客户端时,自动触发该事件方法。该方法是 Web Socket API 最重要方法,开发人员可以实现对数据的处理

(5)onerror() :网络异常、服务器中断等导致响应异常,触发该事件方法。


5.HTML5 技术

2007 年 W3C(World Wide Web Consortium,万维网联盟)立项 HTML5,经过八年的时间正式成为规范。HTML5 彻底颠覆了 Flash、IE 霸主的 PC 网络格局,还优化了移动互联网的性能。它新增 manifest 离线存储、Audio 和 Video 流媒体、canvas 和 webbgl游戏以及 Web Socket API 等新特性元素。

(1)Web Workers 是 W3C 在制定 HTML5 草案中提出的,实现多线程的支持。WebWorkers 允许开发者编写后台长时间运行(响应)Java Script,且不会中断页面的其他容器响应。它主要有三个优点:长时间运行、性能理想以及内存消耗低

(2)在某 Java Script 文件代码中,传入另一个 Java Script 文件名作为参数,我们可以 new一个 Worker 实例。HTML5 为 Web Workers 提供非常简单的 API,主要包括 post Message()、onmessage()、onclose()以及 onerror()。其中,post Message()方法用于 worker 间发送消息;onmessage()是 worker 的"onmessage" 事件监听器回调执行方法。

(3)Web Workers 后台运行的特性,特别适合 Web 浏览器对视音频的处理。本文使用Web Workers 传递 Web Socket 数据帧,实现高效地组装、解析以及编解码等过程

(4)Java Script 提供功能强大的数组容器,如 Array、Array Buffer,但都不太适合处理视音频二进制数据。Typed Array 是 HTML5 引入操作二进制数据的一个接口,可以直接操作内存。Typed Array 提供了 setter、getter、set 和 subarray 四个数据操作方法。这4个方法如下解释:


Typed Array Typed Array 数据操作方法

5.1 Typed Array

Typed Array 一般都建立在 Array Buffer 对象之上。这里简述 Typed Array 定义过程。

(1)首先,通过 Array Buffer,创建指定长度的连续内存区域的对象。接着,基于 Array Buffer对象,我们创建多种类型的“视图”,即 Typed Array 对象。

(2)Typed Array 类型以类型+长度+Array 命名,常用的有:Int8Array、 Uint8Array、Int16Array、 Uint16Array、Int32Array、Uint32Array、Float32Array 以及 Float64Array。

(3)Typed Array 操作二进制数据十分高效。还可以使用Typed Array 的 Data View进行更复杂的二进制操作。


6. Nginx讲解

Nginx 是目前 Web 领域中最出色的 Server 之一,提供一种基于事件驱动、全异步处理以及非阻塞机制的平台,善于处理高并发和实时请求应用。前面文章列表中给出了Nginx源码分析,也可以参考前面的文章。

本文从Nginx的跨平台,容器库和独创性三个角度,研究和分析Nginx“独创”数据结构的设计原理和特色。还会重述Nginx架构设计,包括启动框架、事件框架/第三方RTMPm=模块的RTMP框架。

6.1 Nginx数据结构

Nginx 实现了跨平台特性,自造了大量且高性能的容器库,优化和改进了不少 C 语言数据类型,独创了很多“Nginx 特色”的数据结构。

6.1.1 基础数据结构跨平台

Nginx 对 C 语言数据类型在每一种操作系统都给出了一份特异化的实现。下面以有符号整型(ngx_int_t)为例, 如下图所示。Nginx 对 int(Windows)、intptr_t(Linux)等“有符号整型”进行 typedef 的封装,实现一种跨平台类型 ngx_int_t。当 Nginx 在启动的时候,通过执行 auto/os 下脚本检测操作系统环境,进而选择对应的平台上 C 语言类型。在 Nginx 模块开发中,当确定为 Linux 平台,可以使用 intptr_t、u_char 等系统强相关的 C 语言类型。但是仍然强烈建议采用 Nginx 提供数据类型,因其具有跨平台特性。

ngx_int_t 类型跨平台原理

6.1.2 容器库

STL(Standard Template Library,标准模板库)为 C++开发者提供了 vector、list、set和 map 等容器。作为由 C 实现的 Nginx,无法直接使用 STL 中高性能的容器。为了让Nginx 开发人员享有类似的容器,Igor Sysoev 参考了 STL 使用 C 语言重新实现了一套带有 Nginx 特色的容器。ngx_array_t、ngx_list_t、ngx_queue_t、ngx_rbtree_t 以及 ngx_hash_t等等。

ngx_list_t 是一种存储数组的单链表,可以看成普通数组与 STL 提供 list 的结合体,内存结构如下图所示:


ngx_list_t 内存图

ngx_list_t 与 list 具有类似功能和作用,但是 ngx_list_t 设计更加巧妙,因而性能更好

(1)ngx_list_t 可以存放任意类型数据类型,只需使用成员 size 指定类型大小。

(2)ngx_list_t 使用内存池 pool 统一管理内存,并且链表的每个 part 为固定长度的数组,数组所占用的空间 size*nalloc

(3)ngx_list_t 局部使用数组访问元素,大大提高了访问的效率全局采用单链表方式,便于快速添加、删除等操作。

注意:这种思想是非常值得学习和借鉴,但是实现复杂度有提高了。


6.1.3 独创性

(1)C 语言中,字符串类型必须以’>C 语言中,字符串类型必须以’\0’字符(空字符)结尾。Nginx 创造了一种带长度的字符串类型 ngx_str_t,在路径src/core/ngx_string.h定义源码如下:<’字符(空字符)结尾。Nginx 创造了一种带长度的字符串类型 ngx_str_t,在路径src/core/ngx_string.h定义源码如下:

typedef struct{
size_t  len;//字符串的长符
  u_char *data;//字符串的首地址
}ngx_str_t;

这种设计,可以有效的减少内存资源的使用。一个长度为 100 的字符串使用 C 字符串需要空间大小为 101bytes。若采用 ngx_str_t,仅仅占用 sizeof(size_t)+sizeof(u_char*)大小空间(假设 64 位 OS,空间大小为 8+8=16bytes)。这种设计,同时便于保持字符串的同步。当我们定义字符串时候,我们只分配一份字符串空间。该字符串的所有使用者都是通过首地址和长度来操作,因此每个使用者都对同一份字符串进行操作。


(2)Nginx 还独创了一种内存池(ngx_pool_t)类型,其提供一种机制,帮助统一管理一系列资源(如内存、文件等),以免遗漏。通过使用内存池,将多次向系统申请内存的操作整合成一次,避免出现内存碎片、减少 cpu 资源的消耗。

(3)ngx_buf_t 也是 Nginx 独创的一种数据结构,可以指向内存某缓冲区也可以指向文件某一部分,还可以是纯元数据。ngx_buf_t 本质上提供仅仅是一些指针成员和标志位,并且标志位的设置和使用可以根据实际应用灵活变动。作为一般的使用者,我们只需要掌握常用的部分成员,如 pos、last、end、temporary、last_buf,如下图所示:

ngx_buf_t


还有ngx_listening_t、ngx_event_t、ngx_connection_t 以及 ngx_http_request_t,可以参考前面的文章,如果还没讲到的,以后再讲。


6.2 Nginx 框架

在 Nginx 中,除了一些核心代码以外,其余代码都是以模块的形式出现。目前,Nginx官方提供 6 种核心模块,如 ngx_core_module、ngx_http_module 以及 ngx_events_module在核心模块中可自由定义全新的模块类型。官方还提供大量的非核心模块,可分为四类:配置模块、事件模块、HTTP 模块和 MAIL 模块。除此之外,Wiki 论坛还为 Nginx提供大量的第三方模块,如 nchan。所有模块之间都是分层次、分类别,各类模块的结构如下图所示:


Nginx 模块结构

6.2.1 启动框架

启动框架说明了 Nginx 启动过程,是 Nginx 一切应用的基础。启动从 core/nginx.c文件中 main 函数启动的,启动全部过程都与 ngx_cycle_t 类型全局变量 ngx_cycle 有关。启动过程如下所示:

(1)根据命令行参数得到配置文件路径

(2)如果需要平滑升级,调用ngx_add_inherited_socket方法 。

(3)调用所有核心模块的create_conf方法生成存放配置项的结构体

(4)通过nginx.conf解析配置项,解析过程按照树深度递归。

(5)调用所有核心模块的init_conf方法。

(6)添加文件或目录,初始化shared_memory

(7)调用ngx_open_listening_sockets方法,打开所有监听端口。

(8)调用所有模块的init_module方法

(9)检测Nginx是否运行。

(10)如果运行了,就进入master-worker多进程模式。先运行master进程。接着调用worker进程,调用所有模块的init_process方法,紧接着启动cache manager进程,最后启动cache loader子进程

(11)若还没有运行就先进入单进程模式。调用所有模块的init_process方法。


第 3-8 步实现 ngx_cycle 的初始化,被封装于 ngx_init_cycle 函数。该函数除了对各种 ngx_array_t、ngx_list_t 成员初始化外,还包括:创建、解析所有核心模块配置,打开所有监听的套接字调用所有模块初始化方法

启动框架根据全局变量 ngx_process值,选择 Nginx 工作循环,图中为 9 步以后操作。工业生产中,建议使用 master-worker多进程模式Master 进程执行 process cycle 启动监控、管理子进程,还会调用所有模块 init_process 方法来初始化对应 worker 进程Worker 进程执行 process cycle,处理网络定时器等事件,主要调用事件框架中 ngx_process_events_and_timers()方法工作。

Nginx 启动过程还有一个非常重要的工作:解析配置项。Nginx 设计了一种最底层的模块 NGX_CONF_MODULE 类型,用于解析所有模块的配置项。Nginx 对配置项解析方法 ngx_conf_parse()是以树形式,按树层次遍历递归进行解析,如下图所示:


Nginx Nginx解析配置项

6.2.2 事件框架

Nginx 的高性能在某种程度上要归功于其优秀的事件框架。事件框架可分为网络事件模块和定时器事件模块。本文介绍网络事件模块,可分为 3 层次,如下所示:

(1)第一层:ngx_events_module属于核心模块。定义事件类型模块接口、解析”events{}”块配置项、定义回调 set 方法管理所有事件模块配置项的结构体(创建、解析与初始化)。核心模块 ngx_events_module 的 set 方法处理流程如下图所示:


ngx_events_module ngx_events_module模块的流程图


(2)第二层:ngx_event_core_module,第一个事件模块创建连接池(包括读|写事件)、决定事件驱动机制初始化所选用的事件驱动模块。第二层模块大部分功能都是 ngx_event_process_init()实现,方法流程如下图所示:


ngx_event_process_init 方法流程

ngx_event_process_init 方法在启动框架中调用。nginx 在启动阶段就预设分配好所有的连接(组成连接池),当有客户端产生连接时只需直接从连接池中获取即可使用。配置指令 use 设置所选择的事件模块得序号(即 ctx_index),ngx_event_process_init 方法仅仅在所有的事件模块中 ctx_index 序号的事件模块。ngx_event_process_init 方法将连接的读事件设为 ngx_event_accept,并将这些读事件添加到事件驱动模块中,进而具体的事件驱动模块会检测监听服务,处理用户新连接。

(3)第三层:ngx_select_module,事件驱动实际处理模块,共 9 种,常用 epoll 模块。

其它:ngx_epoll_module、ngx_kqueue_module等等。基于 OS 的系统调用,每个模块都实现事件类型模块接口所定义的 10 个抽象方法,如 init、add、del以及 process_events 等。

(4)事件框架的 ngx_process_events_and_timers 方法,在启动框架中 worker 的工作循环中调用,循环处理所有的事件,是事件驱动机制的核心。主要包括 3 项工作,如下:

第一,调用所选择的事件驱动模块的process_events方法,处理网络事件。

第二,处理两个post事件队列中的事件。

第三,处理定时器事件。


对于事件框架,Nginx 开发者需要熟悉事件模块常见的外部使用方法,如下所示:


事件模块中常见的外部接口事件模块中常见的外部接口

7.RTMP 框架

RTMP 框架是 Nginx 的第三方模块“nginx-rtmp-module”,包含几十个源文件,使Nginx 成为一种支持 RTMP 协议的 Flash 服务器。目前,RTMP 框架具有支持 flv/mp4 视频流、支持 push and pull 分发模式、支持 H264/ACC 编码、支持 HLS、支持 FFmpeg 转码及支持 exec 等功能。RTMP 框架可细分为 ngx_rtmp_module、ngx_rtmp_core_module等数十个模块,这些模块构成了 RTMP 四层次体系,如下图所示:


RTMP RTMP框架体系

下面给出 RTMP 框架基于事件的执行流程,如下图所示:

RTMP RTMP执行流程

8.总结

本文介绍了视频会议的PC客户端和web端的相关协议介绍,包括TCP、RTP/RTCP、RTMP及WebSocket协议。接着介绍了HTML5标准Web Worker和Type Array技术。最好介绍了Nginx,RTMP的相关流程分析。接下来的文章会讲讲多协议之间如何设计。欢迎关注,收藏,转发,分享。

后期关于项目知识,也会更新在微信公众号“记录世界 from antonio”,欢迎关注

HTML5实现分片上传GB级大文件源代码,用HTML5实现分片上传GB级大文件代码,用HTML5实现分片上传GB级大文件源码,用HTML5实现分片上传GB级大文件组件,用HTML5实现分片上传GB级大文件控件,用HTML5实现分片上传GB级大文件方案,用HTML5实现分片上传GB级大文件技术,用HTML5实现分片上传GB级大文件软件,用HTML5实现分片上传GB级大文件服务,用javascript实现分片上传GB级大文件源代码,用js实现分片上传GB级大文件源代码,用vue2实现分片上传GB级大文件源代码,用vue3实现分片上传GB级大文件源代码,

用户上传的文件比较大,有20G左右,直接用HTML传的话容易失败,服务器也容易出错,需要分片,分块,分割上传。也就是将一个大的文件分成若干个小文件块来上传,另外就是需要实现秒传功能和防重复功能,秒传就是用户如果上传过这个文件,那么直接在数据库中查找记录就行了,不用再上传一次,节省时间,实现的思路是对文件做MD5计算,将MD5值保存到数据库,算法可以用MD5,或者CRC,或者SHA1,这个随便哪个算法都行。

分片还需要支持断点续传,现在HTML5虽然提供了信息记录功能,但是只支持到了会话级,也就是用户不能关闭浏览器,也不能清空缓存。但是有的政府单位上传大文件,传了一半下班了,明天继续传,电脑一关结果进度信息就丢失了,这个是他们的一个痛点。

切片的话还有一点就是在服务器上合并,一个文件的所有分片数据上传完后需要在服务器端进行合并操作。

功能的话支持20G文件上传和续传,支持秒传,支持文件夹上传,支持在服务端保存文件夹层级结构,支持将文件夹层级结构信息保存到数据库中,支持下载时能够将文件夹层级结构下载下来,支持下载文件夹,下载文件夹支持断点续传,支持VUE2,VUE3,React,支持IE,Chrome和信创国产化环境,比如银河麒麟,统信UOS,龙芯,支持加密传输,包括加密上传,加密下载,加密算法支持国密SM4,支持云对象存储,比如华为云,阿里云,腾讯云,七牛云,AWS,MinIO,FastDFS,需要提供手机,QQ,微信,邮箱等联系方式,提供7*24小时技术支持,提供长期技术支持和维护服务,提供远程1对1技术指导,提供二次开发指导,提供文档教程,提供视频教程。

1.下载示例

https://gitee.com/xproer/up6-vue-cli



将up6组件复制到项目中

示例中已经包含此目录



1.引入up6组件



2.配置接口地址

接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表

参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de



3.处理事件



启动测试



启动成功



效果



数据库