得物直播低延迟探索 | 得物技术

news2024/11/24 12:39:28

1.背景

直播的时效性保证了良好的用户体验,根据经验在交易环节,延迟越低转化效果也会越好。传统的直播延迟问题已经成为了一个不容忽视的问题,高延迟不仅破坏了用户的观看体验,也让主播难以实时获取到用户的反馈。为了进一步优化直播时效体验,我们需要对产生延迟的原因以及整个交互链路有个清晰的认知,才能稳定的实施相关方案。

2.主观体验

我们团队内部观察了其他电商平台的延时,其中 TOP1 的平台,端到端的延迟在 3s 左右,而得物在 5s 左右,提升空间还是比较明显,我们需要进一步明确具体原因。

3.延迟降低有什么好处

3.1  提升交易环节顺畅度

在得物的直播场景中有添加秒杀商品的环节,秒杀商品的倒计时是实时进行的,假如直播画面有将近8s的延迟才能追上,在这一过程中无论是用户还是主播沟通中都会存在gap。在直播过程中用户在延迟高的场景中提问了但是主播迟迟没有反馈,在这个期间用户有可能退出直播间或者跳过这个商品,这个结果无论是对主播或者是对交易转换都不太能接受。

3.2  提升体验,不同用户之间延迟差别太大

A、B两个用户可能在看某一个直播间,A用户可能很早就进直播间了,而B用户是新进来的,但是B用户的延迟却比A用户的低了几秒,A用户看到可能就会怀疑自己手机、网络、APP是不是哪个有问题,造成不好的体验反馈。

4.直播延迟是如何产生的?

要搞清楚延迟是如何产生的,我们势必要了解到其中哪些程序可能出现延迟,并且是可优化的。

主播 --> 云服务器 --> CDN节点 --> 用户

云服务器 --> 主播: 直播内容转码、压缩等处理

CDN节点 --> 用户: 直播内容分发到多个边缘节点

用户 --> 设备: 接收直播内容  -->  显示直播内容

4.1  在这些过程中,可能会产生延迟的地方

(部分解释来源第三方文献)

  • 主播端所使用的采集编码设备可能存在延迟

主要包含编码延迟以及发送缓存引入的延迟,这个环节的延迟优化空间不多,虽然通过调节编码器参数可有效降低编码延迟,但带来的是画质的损失,同时也影响压缩效果,因此多数集中在优化弱网传输,出发点是为了提供用户观看流畅体验,而不仅限于降低延迟

  • 云服务器对直播内容的转码、压缩等处理的时间

对于直播平台而言,实时转码是非常必要的一项技术。通过对视频流进行实时转码,可以将高清视频流优化为多个分辨率,满足不同终端设备的兼容性和带宽需求,并且减小了网络传输的开销。但是,实时转码过程中必然会带来一定的延迟,这是因为:

    1. 转码过程需要对视频流进行分析和处理,比如压缩、格式转换等。这个过程需要一定的计算资源和时间。

    2. 转码后的视频需要重新传输到CDN节点中,再由观众设备进行播放。这个过程可能会受到网络带宽、传输速率等因素的影响,导致一定的延迟。

因此,针对转码延迟的问题,需要在减小延迟和提高视频质量之间进行权衡。采用一些高级的转码算法、减少图片质量降低对视频画质的伤害、优化编码参数等方法,但也同样会带来画质与压缩率的损失,因此这部分延迟需要根据实际场景综合来考虑,如果对延迟要求很高,可以略微调整下。

  • CDN节点的网络传输延迟

不考虑回源的情况,这个环节主要影响延迟的是 gop cache 策略,各类 CDN 厂商称呼都不一致,有的又叫(RTMP、FLV、HLS...)Delay,即在边缘节点缓存一路流最新的几个 gop(一般媒体时长平均为 5 ~ 7s),目的是为了在拉流请求建立时,可以有媒体数据即时发送,优化首帧和卡顿,这样也就导致了播放端收到的第一帧数据就是 5 ~ 7s 前的旧数据,第一帧的延迟就达到了 5 ~ 7s,这个环节是端到端延迟过大的根因

  • 播放器的防卡顿缓存buffer固定延迟n(s)

在直播拉流播放过程中,为了提高播放的流畅度和用户体验,通常进行缓存一部分buffer。缓存是指在播放器开始播放之前,预先加载一定量的视频数据到本地缓存中,以便后续播放时能够快速读取缓存中的数据,避免卡顿和不流畅的现象。这种“预加载”的缓存被称为“缓存buffer”。

缓存buffer大小不同可能会导致延迟时间也不同,常见的缓存buffer大小为2秒或者更小,这意味着播放器会预先从视频源中加载2秒到本地缓存中,等播放器播放到接近缓存末尾时,会再次预加载2秒内容到缓存中,以保证播放的流畅性。

固定延迟是指播放器在接收到网络数据之后,为保证数据正常播放而需要等待一定的固定时间,一般用于防止视频播放过程中的卡顿和不流畅。例如,如果设置的固定延迟为1秒,那么从数据包到达手机端再到数据包真正播放出来这个过程,就需要多等待1秒左右的时间,这就是固定延迟产生的效果。

通常情况下,播放器会自动根据当前的网络环境动态调整缓存buffer大小和固定延迟时间,以保证最佳的播放效果。不过,如果网络环境不太理想,仍有可能出现视频卡顿和不流畅的情况,此时可以通过配置和优化缓存buffer大小和固定延迟时间来改善播放效果。

  • 用户设备的接收、解码等操作产生的延迟

假设用户的设备硬件性能较为低端,在接收和解码直播数据时出现卡顿等问题。为此,可以通过优化码流参数,如对码率、分辨率等进行调节,使其更加适应用户设备的硬件性能;或者采用尽量少的传输协议,以减少解码时间和相关计算资源的使用。

  • 综合所述

其中任何一个环节出现问题,都有可能导致直播过程中产生延迟。为了减少这种延迟,可以优化各个环节的处理效率,并优化网络传输等方面的参数和设置。

在直播的传输环节里,对延迟影响大的主要是CDN的传输、转码、分发和播放缓冲,使用实时的转码模式,转码器引入的延迟一般在 300ms 以内甚至更短。CDN 的分发环节也会带来一定的延迟,但相对也较短。而为了对抗网络抖动引入的播放缓冲区引入的延迟播放缓冲引入的延迟常常会有 5s 甚至更多。

4.2  如何知道具体延迟?

  • 方法一:

采用端到端的测试方法,即计算播放端推流端的时间差作为延迟。

找一个在线的精确到毫秒的时钟:http://www.daojishiqi.com/bjtime.asp

A. 打开上述网页,推流端对准该网页或者抓取窗口

B. 播放端:到对应直播间观看对应的时间差

对A、B(屏幕)进行对比,截图计算时间差。

  • 方法二:

编码的时候把时间戳写到 SEI 信息中,播放器通过拉流成功后解析 SEI 信息然后与当前时间戳做差值对比。

SEI 需要涉及到推拉流侧底层开发,所以暂选的方法一进行测试,测试结果发现现阶段最保守以及快速的解决方式是直接调整云直播控制台的延迟档位。如果要调整延迟档位,那势必要了解到调整之后会带来什么影响以及变化,这其中就涉及到了 GOP 相关的知识点。

4.3  GOP  以及 GOP cache 是什么?我们为什么要了解它?

顾名思义 GOP cache,是一组存于 CDN 服务端的 GOP 缓存,GOP cache 越大延迟影响也越大。通过了解 GOP cache 我们能在直播延迟链路中能做出更精准的优化。GOP cache 是某一方厂商提出的名词,各大 CDN 的称呼也不一致,有的云厂商又称之为(RTMP、FLV、HLS...)Delay。与推流 GOP 或者 转码播流 GOP 配合,就形成完整的端到端延迟。

  • GOP(Group of Pictures)

而 GOP 是一组连续的视频帧,通常包括一个I帧(关键帧)和若干个P帧(预测帧)和B帧(双向预测帧)。在直播过程中,如果 GOP 的大小过大,会导致接收端在等待I帧的到来时需要等待相对较长的时间,这就会增加视频的延迟。因此,降低 GOP 大小可以在一定程度上减小视频的延迟。

  • 直播控制台的延迟(GOP cache) 配置路径 (域名配置->直播延迟配置) 选项中选择

  • 推流 GOP & 转码 GOP 关系

    • 无转码的情况下,推流 GOP == 播流的 GOP

    • 有转码的情况下,如果转码模板配置了 GOP ,则播流的 GOP == 转码配置的 GOP

    • 如果转码模板未指定具体的 GOP,则推流 GOP == 转码后的 GOP

  • 延迟配置的描述,强调的都是推流 gop,是否有误导问题?

不算完全算误导,一方面不是所有直播流都走转码,甚至修改 GOP。另一方面推流 GOP 对流传输效率可能存在一定影响。主要描述没有把转码 GOP 的影响和区别包括进去。

  • 缓存的单位 duration or size?

得物使用的直播缓存的单位是 duration

在直播延迟中,缓存的单位可以是时间(duration)或大小(size)。

以时间(duration)为单位的缓存指的是,在视频采集、编码和推送到云服务器的过程中,视频数据会先被存放在缓冲区中,等待一定的时间(也就是缓存时间)后,才会被推送到CDN分发节点上进行播放。

以大小(size)为单位的缓存则是根据缓存容量进行控制,视频在采集、编码和推送到云服务器的过程中,每当视频数据达到一定的大小,就会被推送到CDN分发节点上进行播放。

在实际的直播过程中,通常会综合使用时间和大小两种缓存单位来进行延迟控制。如果对延迟比较在意,可以适当增加缓存时间和大小,保证接收端有足够的缓存时间进行播放,减少出现卡顿和停顿的概率。如果实时性比较重要的话,可以适当降低缓存时间和大小,缩短延迟时间,保证直播的实时性。

需要注意的是,缓存时间和缓存大小是直播平台优化延迟的两个关键因素。合理的设置能够显著减小延迟,提升用户体验。但同时,缓存过多或者过少都可能会带来一定的问题,因此需要根据实际情况进行调整和优化。

  • 缓存的 gop 数?

不固定,且没有 GOP 数量的概念,是以时长论大小,取决于 CDN 侧的 buffer ,不管 buffer 多大,发送数据是按照至少一个 delay, 最多 delay + gop 发送的,流数据是不断产生新数据的,发送的时候内容不断在滑动。对延迟没有直接的影响关系。

  • 基础时间值

RTMP :低(2s)中(4s)高(8s)

FLV     :低(2s)中(4s)高(8s)

计算延迟方式:[RtmpDelay, RtmpDelay + GOP] 这里的 GOP,转码前用的推流设置的 GOP,转码后用的转码模板配置的 GOP自定义模版配置的 1080p,gop = 10s = 200桢  的情况下 理论上最小最大值就下面的几种范围[2,12],[4,14],[8,18]

flv 播放的话,delay设置2秒,gop 设置1秒,理论上端到端的延迟基本在3秒左右,如果码率高的情况下,还得适当提升 delay 的值保证直播的流畅。另外除了 CDN 缓存延迟以外,播放器缓存策略也需要考虑。

如果要实现稳定2秒,可以考虑超低延迟直播的方案。

5.后续可实施的有效降低直播延迟手段

  • 降低 CDN 正式环境的 gopCache 至低档位

调整完之后端到端延迟预计能从 5s-8s 降低至 3s-5s

  • 推流 GOP 调整为 1s,平均端到端延迟再下降 1s

理论上来说降低推流 GOP,是对延迟有帮助的,将 GOP 降至1秒,则每秒会推送一个关键帧,接收端就可以在接收到关键帧后直接播放,进一步减小延迟。同时,由于每秒会推送更多关键帧,对视频的画质和稳定性也会产生积极的影响。

推流 GOP 的大小不是唯一的影响直播延迟的因素。还有视频编码、推流服务器的    配置、网络环境等因素都会对延迟产生影响,因此只有在综合考虑到各种因素后,合理设置推流GOP大小,才能够最大程度地降低直播延迟。

  • 增加 buffer 中视频数据的消费速度,有效降低延迟,例如倍速播放或者直接丢帧,策略需要更精细化

也就是说增加拉流侧的消费速度,在有需求的情况下配合倍速追桢的策略,加快视频的播放速度,在某一个阀值中开启或者停止。

推流侧在推流的过程中把关键帧打入时间戳到 SEI 信息里去

拉流侧在拉流的过程中解码成功之后把对应的 SEI 信息里的时间戳解析出来

然后根据服务端的在线时间对比两者之差,决定播放器的播放器倍速,例如 (1.0 ~ 1.4s) 之间逐渐增加和递减,最终在符合预期的延迟时间停止加速消费

  • 确认自研播放器 buffer 缓存当前现状是多少秒,对齐竞品至少 2s buffer

常见的直播播放器缓存buffer大小为2秒,主要是出于减少卡顿和停顿的概率,提升用户体验的考虑。

播放器缓存buffer是指播放器预先缓存一定量的视频数据进行播放。当网络状况不好、视频流传输中断或者延迟过高时,播放器缓存就会派上用场,保证播放过程的连续性和流畅性。

一般来说,播放器缓存buffer大小会根据网络环境和带宽等因素而不同。如果缓存过小,会导致卡顿和停顿;如果缓存过大,会增加延迟,影响实时性。经过优化,常见的直播播放器缓存buffer大小为2秒左右,既能够保证播放过程的流畅性,又不会过度增加延迟。

不同的直播平台(PC、移动端)、不同的网络(WIFI、4G、5G)和设备(不同厂商)可能会有不同的播放器缓存 buffer 大小设置,因此在实际使用中需要根据具体情况进行调整和优化。

  • 使用阿里云的 RTS 或者,字节的 RTM 协议,如果使用超低延时方案还需确认使用场景(例如头部热门直播间有需要的才采用)

阿里云的 RTS(Real-Time Streaming)和字节的 RTM(RTM,Real Time Media)都是超低延时商业化方案,有着使延迟降低至<=1s的效果, 在具体的应用场景和功能方面都差不多。

    1. RTS全链路延时监控、CDN 传输协议改造、UDP 等底层技术优,可以提供低延迟的流媒体数据传输和处理服务,支持高并发、低卡顿、秒开流畅的直播体验。

    2. RTM通过链路传输协议改造为 UDP 等底层技术优化,解决 TCP 协议自身局限和网络抖动引起延迟累加,支持高并发、高可靠性的优质直播观看体验。

以上两种商业化方案都需要配合播放器SDK使用,且 RTM 需要配合火山 CDN 环境使用,两者费用也不一样。需要针对我们当前架构和现状作出权衡考虑。

  • 使用 QUIC 协议(底层UDP协议理论上延迟会更低),已在三方播放器上验证过。普通 flv <=5s 下降到 <=2s

常规直播推流底层协议是基于TCP的,理论上极限在3秒左右已经是最低的了。

而 QUIC(Quick UDP Internet Connections)是一种基于用户数据报协议(UDP)的协议,它在传输上相比于传统的传输层协议(TCP)有以下优势,导致延迟更低:

    1. 连接建立时间短, TCP 协议需要经过三次握手的过程来建立连接,而QUIC协议只需要一次握手,这样就大大减少了连接建立的时间,提高了通信效率。

    2. 报文传输方式不同, TCP 协议在发送数据之前首先需要进行慢启动过程,以逐步增加发送速率并监测网络拥塞。QUIC 协议通过动态地调整窗口大小和传输速率,使得数据传输更加高效。

    3. 多路复用支持度更好, QUIC 协议支持多路复用,这意味着可以在单个连接上同时传输多个流,从而保证更高的带宽利用率和更低的延迟。

    4. 减少网络服务的依赖, QUIC协议能够在连接失效或者网络服务不可用的情况下,进行快速恢复,从而保证了稳定的数据传输。

综上所述,由于QUIC协议在连接建立、报文传输、多路复用和网络故障处理等方面都有着比. TCP协议更好的表现,因此它可以提供更低的延迟,更高的速率以及更可靠的连接。另外一个使用QUIC(UDP)也需要综合考虑一些问题,它带来更低的延迟后,会不会有一些其他方面受到负面影响,例如拉流成功率、稳定性问题之类的。所以最终实施方案还需要做更详细的测试权衡利弊。

6.一些思考

直播延迟问题涉及的因素较多,包括推流端和播放端的缓存设置、传输协议、GOP控制等方面。为了解决延迟问题,在实际开发中,为了达到更好的用户体验,我们需要对这些因素进行综合考虑和优化,在不断的实践和实验中寻找最佳方案,通过综合使用这些技术方案,可以更好地提高直播平台的实时性和观看体验。

文:Brave

活动推荐:

得物技术社招开始啦!点击下方了解活动详情:
社招|得物技术岗位火爆来袭
了解更多精彩文章请点击:得物技术官网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/488865.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机网络(二)】DNS协议

什么是DNS DNS(DOMAIN NAME SYSTEM)是一个域名系统&#xff0c;是万维网上作为域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使用户更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串 DNS 工作流程 客户端发送域名解析请求到本地域名服务器 发…

ESP32(二):GPIO

一.创建例程 打开命令面板&#xff1a;ctrlshiftp&#xff0c;输入&#xff1a;esp-idf:example&#xff1b;选择hello_world工程&#xff0c;点击 Create project using example hello_world&#xff0c;选择保存工程&#xff1b;工具使用代码&#xff1a; #include <stdi…

关于软件卸载

卸载软件 想必大家以前都这样删过软件的吧&#xff1a;把桌面上的图标直接拉进垃圾站 然而想卸载也必然也是因为空间占满了吧 所以今天决定介绍几个卸载的方法和工具。 我也是第一次尝试&#xff0c;毕竟我要毕业了&#xff0c;某些软件我忍他们很久了 浅浅地尝试几个 &am…

压测工具Jmeter

腾讯下载地址&#xff1a;https://mirrors.cloud.tencent.com/apache/jmeter/ index of /apache/jmeter/binaries/xxx.zip 这是windows系统使用 index of /apache/jmeter/binaries/xxx.tgz 这是linux系统使用 安装需要java环境 进到解压文件的bin目录下&#xff0c;双击 jmeter…

【Zynq7010 ebaz4205矿渣变废为宝(此教程包含如何更改PL侧的电路,使得能够正常使用PL侧的资源)】

一、时钟 时钟部分的电路图如下图所示&#xff0c;如果想用PL侧的晶振的话&#xff0c;需要手动焊接一个50MHZ的晶振&#xff0c;并将R1372和L29用0欧姆电阻连通。也可以加上一坨锡连通。我使用的是订书器钉。将订书器钉截取一部分&#xff0c;可以很好的替代0欧姆电阻。 ​ 50…

CTFshow misc PNG隐写入门赛

目录 One PieNG 1 One PieNG 2 One PieNG 3 One PieNG 4 One PieNG 5 One PieNG 6 One PieNG 7 One PieNG 8 One PieNG 9 One PieNG 10 One PieNG 11 One PieNG 12 One PieNG 13 One PieNG 14 One PieNG 15 One PieNG 16 One PieNG 17 One PieNG 18 One Pie…

Python实现哈里斯鹰优化算法(HHO)优化LightGBM分类模型(LGBMClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 2019年Heidari等人提出哈里斯鹰优化算法(Harris Hawk Optimization, HHO)&#xff0c;该算法有较强的全…

Chapter4:频率响应法(中)

第四章:频率响应法 Exercise4.13 已知控制系统的开环对数幅频渐近特性如下,确定各最小相位系统的开环传递函数。 解: 【图 ( a ) ({\rm a}) (a)】 确定系统积分环节或微分环节个数。 因为对数幅频渐近特性曲线的低频渐近线的斜率为

行为型模式-责任链模式

责任链模式 概述 在现实生活中&#xff0c;常常会出现这样的事例&#xff1a;一个请求有多个对象可以处理&#xff0c;但每个对象的处理条件或权限不同。例如&#xff0c;公司员工请假&#xff0c;可批假的领导有部门负责人、副总经理、总经理等&#xff0c;但每个领导能批准…

【SpringMVC】| 使用SpringMVC实现文件上传 | 下载功能

MVC目录 一. &#x1f981; 前言二. &#x1f981; 文件上传 & 下载1. 文件上传Ⅰ. 上传单个文件Ⅱ. 上传多个文件Ⅲ. 异步上传Ⅳ. 跨服务器上传1. 添加跨服上传依赖2. 创建控制器方法 2. 文件下载 三. &#x1f981; 总结 一. &#x1f981; 前言 SpringMVC是一个Web框架…

Qt的UI入门

二、UI入门 1. QWidget类 QWidget类是Qt中所有组件和窗口的基类&#xff0c;其内部规定了组件和窗口的基本规则和功能。 Qt中每个属性的文档中都有Access functions部分&#xff0c;表示其支持的读写&#xff08;getter和setter&#xff09;函数&#xff0c;Qt中的getter和sett…

Redis实现延迟队列方法介绍

延迟队列&#xff0c;顾名思义它是一种带有延迟功能的消息队列。那么&#xff0c;是在什么场景下我才需要这样的队列呢&#xff1f; 1. 背景 我们先看看以下业务场景&#xff1a; 当订单一直处于未支付状态时&#xff0c;如何及时的关闭订单如何定期检查处于退款状态的订单是…

神秘的IP地址8.8.8.8地址到底是什么?为什么会被用作DNS服务器地址呢?

当我们在配置网络连接或者路由器时&#xff0c;经常会遇到需要填写DNS服务器地址的情况。而在这些情况下&#xff0c;很多人都会听到一个神秘的数字地址&#xff1a;8.8.8.8。那么&#xff0c;这个地址到底是什么&#xff0c;为什么会被用作DNS服务器地址呢&#xff1f;本文将详…

分流稳压器TL431/TLV431

分流稳压器&#xff08;Shunt Regulator&#xff09;指的是依靠调节Ik电流来稳定输出电压&#xff0c;分流指的就是Ik来分流。 分流稳压器&#xff0c;也叫做并联电压稳压器&#xff0c;相对地&#xff0c;还有串联电压稳压器。 1、常见型号 TL431TLV431Vref2.5V1.24VVoutVref…

作为一个java工程师,你还记得java的基本数据类型有那些吗?他们的取值范围是多少?

Java是一种强类型编程语言&#xff0c;因此所有的变量都必须先声明后使用。Java基本数据类型指的是Java语言中最基本的数据类型&#xff0c;包括整型、浮点型、字符型、布尔型等。 Java基本数据类型一共有8种&#xff0c;它们分别是&#xff1a; byte&#xff08;字节型&#…

SpringCloud高频面试题--附答案

今天给大家分享SpringCloud高频面试题。下面是一张Spring Cloud核心组件关系图&#xff1a; 从这张图中&#xff0c;其实我们是可以获取很多信息的&#xff0c;希望大家细细品尝。 话不多说&#xff0c;直接开始面试&#xff0c;你准备好了吗&#xff1f; 1、什么是Spring Cl…

汽车电路图、原理框图、线束图、元器件布置图的识读技巧与要点

摘要&#xff1a; 想要读懂汽车电路图就必须把电的通路理清楚&#xff0c;即某条线是什么信号&#xff0c;该信号是输入信号、输出信号还是控制信号以及信号起什么作用&#xff0c;在什么条件下有信号&#xff0c;从哪里来&#xff0c;到哪里去。 一、汽车电路图的识读技巧 1.…

【Python习题集3】常用数据结构习题

数据结构 一、实验内容二、实验总结 一、实验内容 1.从键盘输入一个正整数列表&#xff0c;以-1结束&#xff0c;分别计算列表中奇数和偶数的和。 &#xff08;1&#xff09;源代码 n int(input("请输入一个正整数&#xff1a;")) list3 [] while n ! -1:list3.a…

【云原生|Kubernetes】02-Kubeadm安装部署Kubernetes集群

【云原生|Kubernetes】02-Kubeadm安装部署Kubernetes集群 文章目录 【云原生|Kubernetes】02-Kubeadm安装部署Kubernetes集群前言环境介绍安装kubernetes集群基础环境设置安装Kubernetes集群安装kubeadm&#xff0c;kubectl&#xff0c;kubeletkubeadm初始化集群(master节点操作…

C语言-学习之路-05

C语言-学习之路-05 函数函数分类函数的作用 函数的定义函数定义格式 函数名字、形参、函数体、返回值函数调用无参函数调用有参函数调用 函数的声明多文件&#xff08;分文件&#xff09;编程分文件编程 函数 函数分类 C语言程序都是从主函数main()开始执行的。从函数的定义角…