简介
- 关于windows下C++集成开发工具 Microsoft Visual Studio的学习笔记
项目和解决方案
- 解决方案是一个容器,用于组织一个或多个相关的代码项目,例如,类库项目和对应的测试项目。
- 在Visual Studio中,解决方案不是答案。解决方案仅仅是Visual Studio用来组织一个或多个相关项目的容器。打开某个解决方案时,Visual Studio会自动加载该解决方案包含的所有项目。
栈上分配的对象
堆上分配的对象
静态存储区的对象
__BEGIN_DECLS
和 __END_DECLS
是在C语言和C++代码混合时使用的宏。它们用于确保 C 头文件在被 C++ 编译器编译时能够正确处理 C 函数原型。
当在 C++ 环境中包含 C 头文件时,需要用 extern "C"
来告诉 C++ 编译器这些声明是 C 语言的,以便正确处理名字修饰(name mangling)。__BEGIN_DECLS
和 __END_DECLS
宏正是为了简化这一过程而设计的。
1 | #ifdef __cplusplus |
这段代码的含义是:
__cplusplus
被定义),则 __BEGIN_DECLS
被定义为 extern "C" {
,__END_DECLS
被定义为 }
。使用这些宏可以这样写一个头文件:
1 | #ifndef MY_HEADER_H |
当这个头文件在 C++ 代码中被包含时,my_function
的声明会被包含在 extern "C"
块中,从而避免了 C++ 名字修饰问题。在 C 代码中,宏会被定义为空,所以对代码没有影响。
看一下笔记,按照笔记复习。
小结
list 相关的笔记
小结
下一步
容器,分为序列容器和关联容器
小结
下一步
C++ 标准模板库(Standard Template Library, STL)是一套功能强大的C++模板类和函数的集合,它提供了一系列通用的,可复用的算法和数据结构。
STL的设计基于泛型编程,这意味着使用模板可以编写出独立于任何特定数据类型的代码。
STL分为多个组件,包括容器(Containers),迭代器(Iterators),算法(Algorithms),函数对象(Function Objects)和适配器(Adapters)等
使用STL的好处
C++标准模板库的核心包括以下重要组件
Containers are used to store the data
Algorithms are used to process the data
Functors are used to write custom algorithms
Iterators are used to navigate through the data
All of them are part of STL
strace
是 Linux 下的一个用于诊断和调试程序的命令,它可以跟踪系统调用和接收的信号。strace
工具允许你查看一个进程执行期间所有的系统调用和它们的返回值,这对理解程序的行为和调试问题非常有帮助。
以下是 strace
的一些常见用法:
跟踪一个程序的系统调用:
1 | strace -o output.txt program_name |
这会启动 program_name
并将所有的系统调用记录到 output.txt
文件中。
跟踪一个已经在运行的进程:
1 | strace -p pid |
其中 pid
是进程的 ID。这会附加到已经运行的进程并开始跟踪它的系统调用。
只跟踪特定类型的系统调用:
1 | strace -e trace=open,read,write program_name |
这将只跟踪 open
、read
和 write
系统调用。
打印每个系统调用所花费的时间:
1 | strace -T program_name |
跟踪系统调用和信号:
1 | strace -c program_name |
这会总结系统调用的次数、出错次数和执行时间。
示例:使用 strace
跟踪 ls
命令的系统调用:
1 | strace ls |
这个命令会在终端中打印出 ls
命令执行期间所有的系统调用和它们的返回值。
strace
是一个非常强大的工具,特别是在调试程序、分析系统性能和排查系统问题时非常有用。
strace
是一个强大的 Linux 工具,用于诊断和调试程序。它能够跟踪系统调用(syscalls)和信号(signals),从而帮助用户了解程序的行为、查找问题根源、调试错误等。以下是 strace
的详细使用说明和示例。
1 | strace program_name |
这会启动 program_name
并在终端上显示其所有系统调用。
1 | strace -o output.txt program_name |
将系统调用输出记录到 output.txt
文件中。
1 | strace -p pid |
其中 pid
是进程的 ID。这会附加到已经运行的进程并开始跟踪它的系统调用。
1 | strace -e trace=open,read,write program_name |
这将只跟踪 open
、read
和 write
系统调用。
1 | strace -e trace=file program_name |
这会跟踪所有与文件操作相关的系统调用,例如 open
、read
、write
等。
1 | strace -e trace=network program_name |
这会跟踪所有与网络操作相关的系统调用,例如 socket
、connect
、send
、recv
等。
1 | strace -T program_name |
在输出中包含每个系统调用所花费的时间。
1 | strace -t program_name |
在每个系统调用前面加上时间戳。
1 | strace -r program_name |
在每个系统调用前面显示相对于前一个系统调用的时间间隔。
1 | strace -c program_name |
程序执行完毕后,输出汇总统计信息。
ls
命令的系统调用1 | strace ls |
输出示例:
1 | execve("/bin/ls", ["ls"], 0x7ffccf5a8c38 /* 20 vars */) = 0 |
假设进程 ID 为 1234:
1 | strace -p 1234 |
open
和 read
系统调用1 | strace -e trace=open,read ls |
execve
: 执行程序。open
: 打开文件。read
: 读取文件。write
: 写入文件。close
: 关闭文件描述符。brk
: 调整数据段末尾位置,用于内存分配。mmap
: 内存映射,用于文件或设备的内存访问。strace
是一个非常强大的工具,特别是在调试程序、分析系统性能和排查系统问题时非常有用。它的输出可以帮助开发者理解程序的行为,找出问题的根源并进行优化。
Zabbix 是一个开源的企业级监控解决方案,旨在监控和跟踪 IT 基础设施的健康和性能。它提供了多种功能来帮助管理员监控网络、服务器、应用程序、云服务等。以下是 Zabbix 的一些主要特点:
全面的监控:Zabbix 能够监控各种类型的网络设备、服务器、虚拟机、云服务和应用程序。它支持多种协议,如 SNMP、IPMI、JMX、HTTP、SSH、Telnet 等。
数据收集和分析:Zabbix 可以收集大量的性能和可用性数据,并对这些数据进行存储和分析。它提供了强大的数据可视化工具,如图表、仪表盘和报告。
告警和通知:Zabbix 支持复杂的告警机制,可以根据预定义的条件触发告警,并通过多种渠道(如邮件、短信、Slack、Telegram 等)发送通知。
自动化和自愈:Zabbix 提供了自动化功能,可以在检测到问题时自动执行预定义的操作,如重启服务或执行脚本,以实现自愈。
高扩展性:Zabbix 设计为高扩展性,可以支持从小型环境到大型企业环境的监控需求。它支持分布式监控和代理模式,能够轻松扩展。
开源和社区支持:Zabbix 是开源软件,拥有活跃的社区和广泛的用户基础。社区提供了大量的插件、模板和文档,帮助用户快速上手和扩展功能。
Zabbix 的灵活性和强大的功能使其成为许多企业和组织选择的监控解决方案。无论是用于监控网络设备、服务器性能,还是应用程序健康,Zabbix 都能提供可靠的支持。
Zabbix 是一个开源的监控软件工具,旨在监控和跟踪 IT 基础设施、网络、服务器、虚拟机、应用程序和云服务的健康状况和性能。它提供了一整套功能,从数据收集、存储、分析到告警和自动化操作。由于其高扩展性和灵活性,Zabbix 可以满足从小型组织到大型企业的不同需求。
Zabbix 是一个功能强大且灵活的监控解决方案,适用于各种 IT 环境。从网络设备和服务器的监控,到应用程序和云服务的监控,Zabbix 都能提供可靠的支持。通过其全面的数据收集、分析、告警和自动化功能,Zabbix 帮助企业提高 IT 基础设施的可见性和可靠性,从而更好地保障业务的连续性和性能。
以下是一个简单的 Zabbix 使用示例,展示如何安装、配置和使用 Zabbix 来监控一台服务器的基本性能指标。
更新系统包
1 | sudo apt update |
安装 Zabbix 存储库
1 | wget https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.0-2+ubuntu20.04_all.deb |
安装 Zabbix Server、前端和数据库
1 | sudo apt install zabbix-server-mysql zabbix-frontend-php zabbix-apache-conf zabbix-agent |
安装并配置 MySQL 数据库
1 | sudo apt install mysql-server |
进入 MySQL 命令行,创建数据库和用户:
1 | CREATE DATABASE zabbix CHARACTER SET utf8 COLLATE utf8_bin; |
导入初始架构和数据
1 | zcat /usr/share/doc/zabbix-server-mysql*/create.sql.gz | mysql -uzabbix -p zabbix |
配置 Zabbix Server 连接到数据库
编辑配置文件 /etc/zabbix/zabbix_server.conf
:
1 | DBPassword=password |
启动 Zabbix Server 和代理
1 | sudo systemctl restart zabbix-server zabbix-agent apache2 |
在被监控服务器上安装 Zabbix Agent
1 | wget https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.0-2+ubuntu20.04_all.deb |
配置 Zabbix Agent
编辑配置文件 /etc/zabbix/zabbix_agentd.conf
:
1 | Server=<Zabbix Server IP> |
启动 Zabbix Agent
1 | sudo systemctl restart zabbix-agent |
访问 Zabbix 前端
在浏览器中访问 http://<Zabbix Server IP>/zabbix
,按照提示完成初始设置。
登录 Zabbix 前端
使用默认用户名 Admin
和密码 zabbix
登录。
添加主机
Configuration
-> Hosts
-> Create host
。Templates
标签中,选择 Template OS Linux
模板。检查监控数据
Monitoring
-> Latest data
。通过以上步骤,你已经成功安装并配置了 Zabbix 服务器和代理,并添加了一台被监控的服务器。你可以通过 Zabbix 前端界面查看监控数据,设置告警规则,以及创建图表和仪表盘来直观展示数据。
Zabbix 提供了强大的功能和灵活性,可以监控各种类型的 IT 资源和服务。根据实际需求,你可以进一步定制 Zabbix 的配置和功能,以满足特定的监控需求。
推流(Streaming)是指将音视频内容通过网络实时传输到远程服务器或客户端,使得用户可以在不下载完整文件的情况下进行实时播放。推流技术广泛应用于直播、视频会议、在线教育、远程监控等领域。
采集:
编码:
封装:
传输:
分发和播放:
RTMP(Real-Time Messaging Protocol):
HLS(HTTP Live Streaming):
WebRTC(Web Real-Time Communication):
OBS(Open Broadcaster Software):
FFmpeg:
Wirecast:
Streamlabs OBS:
假设你想使用 FFmpeg 将本地视频文件推流到 RTMP 服务器,命令如下:
1 | ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac -strict experimental -f flv rtmp://example.com/live/stream_key |
解释:
-re
:按实时速率读取输入文件。-i input.mp4
:指定输入文件。-c:v libx264
:使用 H.264 编码器。-c:a aac
:使用 AAC 音频编码器。-strict experimental
:允许使用实验性 AAC 编码器。-f flv
:指定输出格式为 FLV。rtmp://example.com/live/stream_key
:RTMP 服务器地址和流密钥。推流技术为各种实时音视频应用提供了基础支持,使得用户能够在不同设备和网络条件下享受到流畅的实时音视频体验。
拉流(Pull Streaming)或取流(Fetching Stream)是指从服务器端获取实时音视频流并在客户端进行播放的过程。与推流(Push Streaming)相对应,拉流是接收端的操作,常用于观看直播、视频会议、监控等场景。
连接服务器:
请求流:
接收流:
解码和播放:
RTMP(Real-Time Messaging Protocol):
HLS(HTTP Live Streaming):
DASH(Dynamic Adaptive Streaming over HTTP):
WebRTC(Web Real-Time Communication):
VLC Media Player:
FFmpeg:
OBS(Open Broadcaster Software):
Web 浏览器:
假设你想使用 FFmpeg 从 RTMP 服务器拉取流媒体并保存到本地文件,命令如下:
1 | ffmpeg -i rtmp://example.com/live/stream_key -c copy output.mp4 |
解释:
-i rtmp://example.com/live/stream_key
:指定输入流地址。-c copy
:直接复制流媒体数据,不进行重新编码。output.mp4
:指定输出文件名和格式。假设你想使用 VLC 播放 HLS 流媒体,可以按以下步骤操作:
1 | http://example.com/live/stream.m3u8 |
拉流技术是流媒体应用的重要组成部分,使用户能够在不同设备和网络条件下实时获取和播放音视频内容,为各种实时互动和直播应用提供了支持。
流媒体服务器是一种专门用于传输和分发音视频内容的服务器。它可以处理实时音视频流的接收、转码、存储和分发,使得用户能够通过网络实时观看或收听音视频内容。流媒体服务器在直播、点播、视频会议和远程教育等场景中发挥着关键作用。
接收推流:
转码:
存储:
分发拉流:
负载均衡:
安全性:
Nginx + RTMP 模块:
Wowza Streaming Engine:
Red5:
Flussonic:
Kurento:
Adobe Media Server:
安装 Nginx 和 RTMP 模块:
1 | sudo apt-get update |
1 | wget http://nginx.org/download/nginx-1.19.6.tar.gz |
配置 Nginx:
/usr/local/nginx/conf/nginx.conf
):1 | worker_processes 1; |
启动 Nginx:
1 | sudo /usr/local/nginx/sbin/nginx |
推流和拉流:
1 | ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac -strict experimental -f flv rtmp://your_server_ip/live/stream_key |
1 | rtmp://your_server_ip/live/stream_key |
流媒体服务器在现代网络音视频应用中起到了至关重要的作用,通过合理的部署和配置,可以实现高效、稳定和安全的实时音视频传输。
在 Linux 上进行循环推流意味着将一个视频文件不断地推送到流媒体服务器,以便进行持续播放。这通常用于 24/7 直播、广告循环播放等场景。使用 FFmpeg
是实现这一功能的常见方法,因为它非常灵活且支持多种音视频处理任务。
如果尚未安装 FFmpeg,请先进行安装:
对于 Debian/Ubuntu 系统:
1 | sudo apt update |
对于 CentOS/RHEL 系统:
1 | sudo yum install epel-release |
以下是一个简单的 Bash 脚本示例,用于实现视频文件的循环推流:
1 | #!/bin/bash |
解释:
RTMP_URL
:指定 RTMP 服务器的推流地址。VIDEO_FILE
:指定要推流的视频文件。while true; do ... done
:无限循环执行推流命令。ffmpeg -re -stream_loop -1 -i "$VIDEO_FILE" -c:v libx264 -c:a aac -f flv "$RTMP_URL"
:-re
:按实时速率读取输入文件。-stream_loop -1
:无限循环输入文件。-i "$VIDEO_FILE"
:指定输入文件。-c:v libx264
:使用 H.264 视频编码器。-c:a aac
:使用 AAC 音频编码器。-f flv "$RTMP_URL"
:指定输出格式为 FLV,并推送到 RTMP 服务器。if [ $? -ne 0 ]; then ...
:如果 FFmpeg 命令失败,等待 5 秒后重试。保存上述脚本为 loop_stream.sh
,然后赋予其执行权限并运行:
1 | chmod +x loop_stream.sh |
有时你可能需要在每次循环结束后对推流进行一些清理工作,或者在推流过程中处理网络中断等情况。可以通过捕捉信号或检查推流状态来实现更复杂的逻辑。例如:
1 | #!/bin/bash |
此脚本在接收到中断信号(如 Ctrl+C
)时会优雅地退出。
supervisord
、systemd
)来确保推流脚本的运行和自动重启。ffmpeg
的 concat
过滤器。以下是一个多文件循环播放的脚本示例:
1 | #!/bin/bash |
此脚本会按顺序循环播放 VIDEO_FILES
列表中的每个视频文件,并在所有文件播放完毕后重新开始。
lz4.h
是 LZ4 压缩库的头文件。LZ4 是一种非常快速的无损压缩算法,专为高性能和高压缩率设计。LZ4 库主要用于数据压缩和解压缩操作,适用于需要快速处理大量数据的应用程序。
LZ4 库的头文件 lz4.h
定义了所有必要的函数和数据结构,使得开发者可以在他们的 C 或 C++ 项目中轻松地使用 LZ4 压缩和解压缩功能。这个头文件通常包含以下内容:
常用的函数包括:
LZ4_compress_default()
LZ4_decompress_safe()
LZ4_compressBound()
这些函数分别用于默认压缩、解压缩和计算压缩缓冲区的最大大小。
以下是一个使用 lz4.h
的简单示例,演示如何进行压缩和解压缩:
1 | #include <stdio.h> |
这个示例展示了如何使用 LZ4 库进行数据的压缩和解压缩操作。
LZ4 库是一个开源的压缩算法库,专注于提供高效、快速的无损压缩和解压缩功能。LZ4 是一种非常快的压缩算法,能够在保持高压缩速度的同时提供良好的压缩率。它特别适用于需要快速处理大量数据的应用程序,例如日志压缩、传输数据的实时压缩、存储系统等。
LZ4 库具有以下几个主要特点:
LZ4 库主要提供了两个核心函数:LZ4_compress_default
和 LZ4_decompress_safe
。
LZ4_compress_default
函数用于压缩数据:
1 | int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); |
source
:指向要压缩的源数据。dest
:指向压缩后存储数据的目标缓冲区。sourceSize
:源数据的大小。maxDestSize
:目标缓冲区的最大大小。返回值是压缩后的数据大小,如果返回值为 0 或负值,则表示压缩失败。
LZ4_decompress_safe
函数用于解压缩数据:
1 | int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize); |
source
:指向要解压缩的压缩数据。dest
:指向解压缩后存储数据的目标缓冲区。compressedSize
:压缩数据的大小。maxDecompressedSize
:目标缓冲区的最大大小。返回值是解压缩后的数据大小,如果返回值为负值,则表示解压缩失败。
下面是一个简单的示例,展示了如何使用 LZ4 库进行数据的压缩和解压缩:
1 | #include <stdio.h> |
这个示例展示了如何使用 LZ4 库的压缩和解压缩函数来处理字符串数据。
要编译和安装 LZ4 库,你可以按照以下步骤进行。这里假设你使用的是 Unix 系统,例如 Linux 或 macOS。如果你使用的是 Windows 系统,可以参考对应的指南。
首先,你需要从 LZ4 的 GitHub 仓库下载源代码。你可以使用 git
命令来克隆仓库,或者直接从 GitHub 网站下载压缩包。
1 | git clone https://github.com/lz4/lz4.git |
进入 LZ4 源代码目录后,使用以下命令来编译库。LZ4 使用 make
工具来管理编译过程。
1 | make |
这个命令会编译所有的源文件并生成可执行文件和库文件。
编译完成后,你可以使用以下命令来安装 LZ4 库。默认情况下,库会安装到系统的标准位置(例如 /usr/local
)。
1 | sudo make install |
如果你希望将库安装到自定义位置,可以使用 PREFIX
选项来指定目标路径:
1 | sudo make install PREFIX=/path/to/your/installation/directory |
你可以使用以下命令来验证 LZ4 是否安装成功:
1 | lz4 -V |
这个命令会输出 LZ4 的版本信息,表明 LZ4 已成功安装。
在你的 C/C++ 项目中,你需要包含 LZ4 的头文件并链接 LZ4 库。假设你已经安装 LZ4,并且头文件和库文件位于系统的标准位置,你可以使用以下示例代码:
1 | #include <stdio.h> |
编译这个示例代码时,记得链接 LZ4 库:
1 | gcc -o example example.c -llz4 |
通过以上步骤,你应该能够成功地编译、安装和使用 LZ4 库。
LIVE555 是一个开源的多媒体流媒体库,主要用于实现 RTP/RTCP、RTSP 和 SIP 协议。它提供了一系列的 C++ 类,用于创建多媒体流媒体应用程序,例如流媒体服务器和客户端。LIVE555 可以用于流式传输各种多媒体格式,包括 H.264 视频、AAC 音频等。
LIVE555 的主要特点包括:
通常,LIVE555 被用作开发实时流媒体应用程序的基础组件,例如视频监控系统、实时视频会议系统等。
LIVE555 是一个开源的多媒体流媒体库,广泛应用于实时流媒体传输和接收。它由 Ross Finlayson 维护,主要用来处理 RTP/RTCP、RTSP 和 SIP 协议,并支持多种多媒体格式的流式传输。以下是 LIVE555 的详细介绍:
这是 LIVE555 提供的基础环境,处理事件循环和日志记录。它为应用程序提供了一个使用基础 API 的上下文。
该模块处理网络套接字的组播和单播通信,封装了 IP 地址和端口的处理逻辑。
该模块用于实现 RTSP 客户端功能,能够发送 RTSP 请求(如 DESCRIBE、SETUP、PLAY、PAUSE 和 TEARDOWN)并处理 RTSP 响应。
该模块用于实现 RTSP 服务器功能,能够接收和处理来自客户端的 RTSP 请求,并管理媒体流会话。
该模块表示一个媒体会话,包含一个或多个媒体子会话(MediaSubsession),每个子会话表示一个媒体流(例如视频流或音频流)。
该模块处理媒体数据的接收和处理,通常用于播放或保存媒体流。
该模块用于生成媒体数据,可以从文件、设备或其他来源读取数据。
RTP(实时传输协议)用于实时传输多媒体数据,而 RTCP(RTP 控制协议)用于监控数据传输的质量和提供会话控制。
RTSP(实时流协议)是一种网络控制协议,用于建立和控制媒体流会话。RTSP 类似于 HTTP,但专门设计用于流媒体控制。
SIP(会话初始协议)用于建立、修改和终止多媒体会话(如 IP 电话呼叫)。
LIVE555 支持多种多媒体格式的流式传输,包括但不限于:
以下是一个简单的 RTSP 客户端示例代码:
1 | #include <BasicUsageEnvironment.hh> |
这个示例展示了如何创建一个简单的 RTSP 客户端,连接到 RTSP 流媒体服务器并进入事件循环。
通过这些资源,您可以获得更多关于 LIVE555 的详细信息和使用指南。
清理Docker日志的最佳方法是通过Docker提供的内置支持在容器运行时管理日志级别并限制日志大小。但是,如果需要清理已经存在的日志文件,则可以用以下方法
使用Docker命令清理
1 | docker container prune --filter "until=24h" |
手动清理Docker日志
1 | docker container ls -a |
1 | cat /dev/null > /var/lib/docker/containers/容器ID/容器ID-json.log |
1 | docker run -it --log-opt max-size=10m --log-opt max-file=3 alpine ash |
RTSP(Real-Time Streaming Protocol,即实时流传输协议)是一种网络协议,用于控制音频或视频流的传输。RTSP允许客户端从服务器请求媒体流并进行播放、暂停、停止等操作。它通常用于IP摄像头、直播流媒体服务器和其他需要实时流传输的应用场景。
RTSP协议的主要特点包括:
常见的RTSP使用场景包括:
RTSP流的典型URL格式如下:
1 | rtsp://[用户名]:[密码]@[IP地址]:[端口]/[路径] |
例如:
1 | rtsp://user:password@192.168.1.100:554/stream1 |
这表示客户端可以使用RTSP协议连接到IP地址为192.168.1.100的服务器,端口为554,并请求路径为/stream1
的媒体流。
RTP(Real-time Transport Protocol)是用于Internet上针对多媒体数据流的一种传输协议。
RTP协议是建立在UDP协议上的。RTP协议详细说明了在互联网上传递音频和视频的标准数据包格式。RTP协议常用于流媒体系统(配合RTCP协议),视频会议和视频电话系统(配合H.263或SIP)
RTP本身并没有提供按时发送机制或其他服务质量(Qos)保证,它依赖于底层服务去实现这一过程。RTP并不保证传送或防止无序传送,也不确定底层网络的可靠性。
RTP中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。
实时传输控制协议(Real-time Transport Control Protocol, RTCP)是实时传输协议(RTP)的一个姐妹协议。RTCP为RTP媒体流提供信道外控制。RTCP定期在流媒体会话参加者之间传输控制数据。
RTCP的主要功能是为RTP所提供的服务质量提供反馈。RTCP收集相关媒体连接的统计信息,例如:传输字节数,传输分组数,丢失分组数,时延抖动,单向和双向网络延迟等等。
网络应用程序可以利用RTCP所提供的信息试图提高服务质量,比如限制信息流量或改用压缩比较小的编解码器。RTCP本身不提供数据加密或身份认证,其伴生协议STRCP(安全实时传输控制协议)则可以用于此类用途。
RTP(Real-time Transport Protocol,即实时传输协议)是一种网络协议,专门用于通过IP网络传输实时音视频数据。它是由IETF(Internet Engineering Task Force)定义的标准协议,用于在互联网上传输实时媒体流。
RTP协议的主要特点和功能包括:
RTP通常与其他协议一起使用,如:
一个典型的RTP数据包结构如下:
通过这些特性,RTP能够确保实时音视频数据的有效传输和同步,从而在互联网上提供高质量的实时多媒体通信。
RTCP(Real-time Transport Control Protocol,即实时传输控制协议)是一种网络协议,用于与RTP(Real-time Transport Protocol,即实时传输协议)一起工作,提供对实时数据流传输质量的监控和控制。RTCP并不传输媒体数据本身,而是传输控制信息,帮助管理和优化媒体传输。
RTCP的主要功能包括:
传输质量反馈:RTCP提供有关传输质量的反馈信息,如数据包丢失率、延迟和抖动。这些信息可以帮助发送方和接收方调整传输参数,以提高传输质量。
参与者标识:RTCP允许每个参与者报告其标识信息,如名称和邮箱地址。这有助于在多方通信中识别各个参与者。
带宽管理:RTCP可以帮助控制会话的带宽使用。通过反馈信息,发送方可以调整传输速率,以避免网络拥塞。
同步多媒体流:RTCP可以协助同步来自不同源的多个RTP流(如音频和视频),以确保它们在接收端正确地同步播放。
RTCP报文类型主要有以下几种:
SR(Sender Report,发送报告):由RTP流的发送者定期发送,包含发送的RTP包数和字节数,以及与接收者同步的时间信息。
RR(Receiver Report,接收报告):由RTP流的接收者定期发送,包含接收到的RTP包数、丢包率、往返时间等统计信息。
SDES(Source Description Items,源描述项):包含源标识符和相关的文本信息(如参与者的名字)。
BYE:通知结束会话的消息,表示发送者将退出会话。
APP(Application Specific Message,应用特定消息):用于传输特定应用定义的控制信息。
通过与RTP一起使用,RTCP能够提供有效的传输控制和质量管理,确保实时媒体流的传输质量和可靠性。这使得RTCP成为多媒体通信中不可或缺的协议之一。
RTMP(Real-Time Messaging Protocol,即实时消息传输协议)是一种由Adobe Systems开发的协议,主要用于在互联网或局域网上进行音频、视频和数据的实时传输。RTMP最初用于支持Adobe Flash播放器,但现已被广泛用于各种流媒体传输应用,尤其是在直播流媒体中。
RTMP的主要特点和功能包括:
RTMP的传输过程通常分为三个阶段:
RTMP有几个变种,包括:
一个典型的RTMP URL格式如下:
1 | rtmp://[服务器IP或域名]/[应用名称]/[流名称] |
例如:
1 | rtmp://live.example.com/app/stream |
这表示客户端可以使用RTMP协议连接到live.example.com
服务器,请求app
应用中的stream
流。
尽管RTMP已经不再是主流,但它仍然在许多直播平台和视频传输系统中使用。现代替代方案如HLS(HTTP Live Streaming)和DASH(Dynamic Adaptive Streaming over HTTP)在许多新应用中更为常见。
RTMP是Adobe Systems公司为Flash播放器和服务器之间音频,视频和数据传输开发的开放协议。它有三种变种
RTMP视频播放的特点是
HLS(HTTP Live Streaming,即HTTP实时流传输协议)是一种基于HTTP的流媒体传输协议,由苹果公司开发。HLS最早在2009年与iOS 3.0一起发布,现已成为一种广泛使用的流媒体传输标准,适用于直播和点播视频。
HLS的主要特点和功能包括:
HLS工作流程如下:
一个典型的HLS播放列表文件(M3U8)的示例如下:
1 | #EXTM3U |
这个播放列表文件指示客户端依次请求和播放segment0.ts
、segment1.ts
和segment2.ts
,每个片段长度为10秒。
HLS在流媒体行业中得到广泛应用,特别是在直播和视频点播服务中,成为了许多视频传输解决方案的基础。
所谓程序性能(performance of a program)是指运行这个程序所需要的内存和时间的多少。我们用两种方法来确定一个程序的性能,一个是分析方法,另一个是实验方法。在性能分析(performance analysis)时,采用分析方法,而在性能测量(performance measurement)时,使用实验方法。
所谓一个程序的空间复杂度(space complexity)是指该程序的运行所需内存的大小。我们对程序的空间复杂度感兴趣的主要原因如下
所谓程序的时间复杂度(time complexity)是指运行程序所需要的时间。我们对程序的时间复杂度感兴趣的主要原因如下
程序所需要的空间主要由以下部分构成
指令空间的数量取决于如下因素
在决定最终代码需要多少空间的时候,编译器是一个最重要的因素。
即使采用相同的编译器,编译后的程序代码也可能不同。因为一个编译器可能具备优化选项。
编译器的覆盖选项也可以显著的减少程序空间。在覆盖模式下,空间仅分配给当前正在执行的程序模块。调用一个新模块需要从磁盘或者其他设备中读取,新模块代码将覆盖原模块的代码。因此,程序所需要的空间便是最大模块所需要的空间,而不是所有模块所需要的空间之和。
对各种数据类型,C++语言并没有指定他们的空间大小,只是大多数C++编译器有相应的空间分配。
一个结构变量的空间大小是每个结构成员所需要的空间大小之和。类似的,一个数组的空间大小是数组的长度乘以一个数组元素的空间大小。
当计算分配给一个数组的空间时,我们只关心分配给数组元素的空间。数组a的空间是100个double类型元素所占用的空间。若每个元素空间是8字节,则数组a的空间是800字节。数组maze有rows*cols个int类型的元素,占用的空间是4 * rows * cols字节。
在开始性能分析时,人们通常会忽略环境栈所需要的空间,因为他们不理解函数(特别是递归函数)是如何被调用的以及在函数调用结束时会发生什么。每当一个函数被调用时,下面的数据将被保存在环境栈中
值得注意的是,有些编译器,不论对递归函数还是非递归函数,在函数调用时,都会保留局部变量和形参的值,而有些编译器仅对递归函数才会如此。因此实际使用的编译器将影响环境栈所需空间的大小。
程序要处理的问题实例都有一些特征,这些特征都包含着可以决定程序空间大小的因素(例如,输入和输出的数量或相关数的大小)。例如,对n个元素排序的程序,它所需要的空间大小是n的函数,n为其实例特征;将两个n x n矩阵累加的程序,n为其实例特征;把两个m x n矩阵相加的程序,m和n为其实例特征。
相对来说,指令空间的大小受实例特征的影响不大。
可以把一个程序所需要的空间分为两部分
任意程序P所需要的空间可以表示为: c + Sp(实例特征)
在分析一个程序的空间复杂度时,我们将集中计算Sp对任意给定的问题,我们首先要确定哪些实例特征可以用来估算空间需求。选择实例特征是一个很具体的问题,我们需要求助于实际的例子来说明各种可能的情况。一般来说,我们的选择仅限于程序输入和输出的规模。有时我们也会对数据项之间的关系进行复杂的估算。
用分析方法确定一个程序的运行时间是复杂的,因此只能估算运行时间。而且有两个比较容易控制的方法
估算一个程序或函数的时间复杂度,一种方法是选择一种或者多种关键操作,例如加,乘,比较等,然后 确定每一种操作的执行次数。使用这种方法成功与否取决于是否能够找到耗时最大的操作。
从本章开始研究数据结构,一直到第16章为止。第5章和第6章集中研究线性表,但主要是介绍数据的描述方法,即数据在计算机内存和磁盘上的存储方式。在随后的章节中,我们研究其他常用的数据结构描述方法。这些数据结构有矩阵,栈,队列,字典,优先级队列,竞赛树,搜索树和图。
C++程序常用的数据描述方法是数组描述和链式描述。线性表可以用来说明这两种方法。
STL容器(vector和list)大致相当于线性表描述方法和链式描述方法。STL的类还有很多其他的方法。在建立线性表的数组描述和链式描述中,我们使用的函数名和签名与STL代码所使用的相同。
数组描述方法将元素存储在一个数组中,用一个数学公式来确定每个元素存储的位置,即在数组中的索引。这是最简单的一种存储方式,所有元素依次存储在一片连续的存储空间中,这就是通常所说的顺序表。
本章引用的数据结构的概念如下
本章新增的C++概念
数据对象(data object)是一组实例或者值,例如
1 | boolean = {false, true}; |
boolean, digit都是数据对象,true和false是boolean的实例,而0,1—9是digit的实例。
数据对象的一个实例,要么是一个不可再分的原子,要么是由另一个数据对象的实例作为成员复合而成。对后一种情形,用元素(element)来表示这些成员。
数据对象的实例以及构成实例的元素通常都有某种相关性。例如,自然数0是最小的自然数,1是仅比0大的自然数。在串good中,g是第一个字母,o是第二个和第三个字母,而d是最后一个字母。
数据结构(data structure)是一个数据对象,同时这个对象的实例以及构成实例的元素都存在着联系,而且这些联系由相关的函数来规定。
研究数据结构,关心的是数据对象(实际上是实例)的描述以及相关函数的具体实现。数据对象描述的好,函数的实现就会高效。
线性表(linear list)也称有序表(ordered list),它的每一个实例都是元素的一个有序集合。
一个线性表可以用一个抽象数据类型(abstract data type, ADT)来说明,既说明它的实例,也说明对他的操作。抽象数据类型的说明独立于任何程序语言的描述。所有对抽象数据类型的语言描述必须满足抽象数据类型的说明,抽象数据类型的说明保证了程序语言描述的有效性。另外,所有满足抽象数据类型说明的语言描述,都可以在应用中替换使用。
在数组描述(array representation)中,用数组来存储线性表的元素。虽然可以用一个数组存储若干个线性表的实例,但是用不同数组存储每个实例更加容易一些。我们可以用一个数学公式来确定一个线性表的元素在数组中的位置。
假定使用一个一维数组element来存储线性表的元素。数组element的位置有 element[0] — element[arrayLength - 1],其中arrayLength是数组长度或者容量。数组的每一个位置都可以存储线性表的一个元素。我们需要一个映射,使线性表的一个元素对应数组的一个位置。线性表的第0个元素在数组的什么位置?线性表的最后一个元素在数组的什么位置?这种映射可以用下面的一个公式来表示
一维数组a,线性表元素存储在a[0:n-1]中,要增加或者减少这个数组的长度,首先要建立一个具有新长度的数组,然后把数组a的元素复制到这个新数组,最后改变数组a的值,使它能够引用到新数组。
当数组满而需要加大数组长度时,数组长度常常是要加倍的。这个过程称为数组倍增(array doubling)。数组倍增的时间,从渐近意义上考量,不会大于元素插入的总时间。
为什么数组长度不是增加1或2,而是要加倍呢?数组长度每次增加1或2,虽然不影响插入操作的最坏时间复杂度,但是影响连续插入时的渐近时间复杂度。
定理:如果我们总是按一个乘法因子来增加数组长度,那么实施一系列线性表的操作所需要的时间与不用改变数组长度时相比,至多增加一个常数因子。
一个迭代器(iterator)是一个指针,指向对象的一个元素(例如,一个指向数组元素的指针)。顾名思义,一个迭代器可以用来逐个访问对象的所有元素。
迭代器是编写C++通用算法的基础概念。STL的copy函数便是用来复制任何具有迭代器的对象的元素。
为了简化迭代器的开发和基于迭代器的通用算法的分类,C++的STL定义了5中迭代器:
所有迭代器都具备操作符 == , != 和解引用操作符 *
另外,输入迭代器还提供了对其指向元素的只读操作以及前++和后++操作符。输出迭代器提供了对其指向元素的写操作和++操作符。向前迭代器具有++操作符,而双向迭代器既具有++操作符也具有–操作符。随机访问迭代器是最一般的迭代器,它既可以随意的实现跳跃移动,也可以通过指针算术运算来实现跳跃移动。
描述
每一个节点只有一个链,这种结构称为单向链表(singly linked list)。链表从左到右,每一个节点(最后一个节点除外)都链接着下一个节点,最后一个节点的链阈值为NULL。这样的结构也称为链条(chain)
结构chainNode
类chain
一个m * n的矩阵(matrix)是一个m行,n列的表,m和n是矩阵的维数(dimension)
矩阵通常用来组织数据。
矩阵最常见的操作是矩阵转置,矩阵相加,矩阵相乘。
两个矩阵仅当维数相同时(即它们的行数和列数都分别相等)才可以相加。两个m * n的矩阵A和B相加之后是一个m * n的矩阵C
一个m * n的矩阵A和一个q * p的矩阵B,只有当A的列数等于B的行数(即n=q)时,才可以相乘AB。AB的结果是一个m * p的矩阵C
特殊矩阵
一个m * n的矩阵,如果大多数元素都是0,则称为稀疏矩阵(spare matrix)。一个矩阵如果不是稀疏的,就成为稠密矩阵(dense matrix)
栈和队列很可能是应用频率最高的数据结构。在第五章和第六章曾经广泛研究了线性表和有序表数据结构,而栈和队列是它们的限制版。
栈和队列的应用广泛,以至于C++的标准类模板库STL都提供了用数组实现的栈和队列。
把线性表的插入和删除操作限制在同一端进行,就得到栈数据结构。因此,栈是一个后进先出(last-in-first-out, FIFO)的数据结构。因为栈是一种特殊的线性表,所以从相应的线性表类派生出栈类是很自然的事情。
栈(stack)是一种特殊的线性表,其插入(也称入栈或压栈)和删除(也称出栈或弹栈)操作都在表的同一端进行。这一端称为栈顶(top),另一端称为栈底(bottom)
计算机是如何执行递归函数?
抽象数据类型
1 | template<class T> |
return,它的主要任务是在函数结束时将控制权交还给调用他的代码。
return不仅可以返回基本数据类型,还可以返回复杂的数据结构,例如对象和数组。
合理使用return,可以使代码更加简洁明了。在进行条件判断时,我们可以在条件满足时立即返回,避免不必要的嵌套。
exit,它不仅仅是结束当前的函数,而是终止整个程序的执行,立即返回给操作系统。
应急处理和日志记录。在一些关键任务中,遇到不可恢复的错误时,我们可以使用exit来终止程序,并在退出前记录错误日志,以便后续分析。
注册清理函数。使用atexit函数,我们可以在程序终止时执行一些清理工作,例如释放资源或者保存程序状态
作用范围
清理操作
使用场景
综合考虑