.引言
本篇文章也涉及到很多知识点,如果对于细节部分不是很了解,可以阅读前面的文章,能够帮助你更加理解本篇文章。通过系列文章来讲解,本篇文章是第一篇。参考文章内容列表如下:
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 表示 Double、02 表示 String。AMF 数据包括 AMF0、AMF3。
(8)Message Type ID 为 20 表示 RPC(Remote Procedure Call,远程过程调用)命令消息,主要分为 Net Connection 和 Net Stream 两大类型。前者包括 connect、call、close 与create 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 Socket,Sec-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_FRAME 等 9 种帧类型。
(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.处理事件
启动测试
启动成功
效果
数据库
*请认真填写需求信息,我们会在24小时内与您取得联系。