鸿蒙轻内核M核源码分析系列五 时间管理

往期知识点记录:

  • 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
  • 持续更新中……

在鸿蒙轻内核源码分析上一篇文章中,我们剖析了中断的源码,简单提到了Tick中断。本文会继续分析Tick和时间相关的源码,给读者介绍鸿蒙轻内核的时间管理模块。本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。

时间管理模块以系统时钟为基础,可以分为2部分,一部分是SysTick中断,为任务调度提供必要的时钟节拍;另外一部分是,给应用程序提供所有和时间有关的服务,如时间转换、统计功能。

系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”,也称为时标或者TickTick是操作系统的基本时间单位,由用户配置的每秒Tick数决定。如果用户配置每秒的Tick数目为1000,则1个Tick等于1ms的时长。另外一个计时单位是Cycle,这是系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数,对于216 MHzCPU,1秒产生216000000个cycles

用户以秒、毫秒为单位计时,而操作系统以Tick为单位计时,当用户需要对系统进行操作时,例如任务挂起、延时等,此时可以使用时间管理模块对Tick和秒/毫秒进行转换。


下面,我们剖析下时间管理模块的源代码,若涉及开发板部分,以开发板工程targets\cortex-m7_nucleo_f767zi_gcc\为例进行源码分析。

1、时间管理初始化和启动

我们先看下时间管理模块的相关配置,然后再剖析如何初始化,如何启动。

1.1 时间管理相关的配置

时间管理模块涉及3个配置项,系统时钟OS_SYS_CLOCK、每秒Tick数目LOSCFG_BASE_CORE_TICK_PER_SECOND两个配置选项,还有宏LOSCFG_BASE_CORE_TICK_HW_TIMELOSCFG_BASE_CORE_TICK_HW_TIME默认关闭,开启时,需要提供定制函数VOID platform_tick_handler(VOID),在Tick中断处理函数中执行定制操作。这些配置项在模板开发板工程目录的文件target_config.h中定义,如文件targets\cortex-m7_nucleo_f767zi_gcc\target_config.h中定义如下:

#define OS_SYS_CLOCK                                        96000000
#define LOSCFG_BASE_CORE_TICK_PER_SECOND                    (1000UL)
#define LOSCFG_BASE_CORE_TICK_HW_TIME                       0

1.2 时间管理初始化和启动

函数INT32 main(VOID)会调用kernel\src\los_init.c中的函数UINT32 LOS_Start(VOID)启动系统,该函数会调用启动调度函数UINT32 HalStartSchedule(OS_TICK_HANDLER handler)。源码如下:

LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID)
{
    return HalStartSchedule(OsTickHandler);
}

函数UINT32 HalTickStart(OS_TICK_HANDLER *handler)定义在kernel\arch\arm\cortex-m7\gcc\los_context.c,源码如下。其中函数参数为Tick中断处理函数OsTickHandler(),后文会分析该tick中断处理函数。⑴处代码继续调用函数进一步调用函数HalTickStart(handler)来设置Tick中断启动。⑵处会调用汇编函数HalStartToRun开始运行系统,后续任务调度系列再详细分析该汇编函数。

LITE_OS_SEC_TEXT_INIT UINT32 HalStartSchedule(OS_TICK_HANDLER handler)
{
    UINT32 ret;
⑴  ret = HalTickStart(handler);
    if (ret != LOS_OK) {
        return ret;
    }
⑵  HalStartToRun();
    return LOS_OK; /* never return */
}

函数HalTickStart(handler)定义在文件kernel\arch\arm\cortex-m7\gcc\los_timer.c,源码如下,我们分析下函数的代码实现。⑴处校验下时间管理模块的配置项的合法性。在开启宏LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT时,会使用系统定义的中断。会执行⑵处的代码,调用定义在文件kernel\arch\arm\cortex-m7\gcc\los_interrupt.c中的函数OsSetVector()设置中断向量,该函数在中断系列会详细分析。⑶处设置全局变量g_sysClock为系统时钟,g_cyclesPerTick为每tick对应的cycle数目,g_ullTickCount初始化为0,表示系统tick中断发生次数。⑷处调用定义在targets\cortex-m7_nucleo_f767zi_gcc\Drivers\CMSIS\Include\core_cm7.h文件中的内联函数uint32_t SysTick_Config(uint32_t ticks),初始化、启动系统定时器Systick和中断。

WEAK UINT32 HalTickStart(OS_TICK_HANDLER *handler)
{
    UINT32 ret;

⑴  if ((OS_SYS_CLOCK == 0) ||
        (LOSCFG_BASE_CORE_TICK_PER_SECOND == 0) ||
        (LOSCFG_BASE_CORE_TICK_PER_SECOND > OS_SYS_CLOCK)) {
        return LOS_ERRNO_TICK_CFG_INVALID;
    }

#if (LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT == 1)
#if (OS_HWI_WITH_ARG == 1)
    OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler, NULL);
#else
⑵  OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler);
#endif
#endif

⑶  g_sysClock = OS_SYS_CLOCK;
    g_cyclesPerTick = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND;
    g_ullTickCount = 0;

⑷  ret = SysTick_Config(g_cyclesPerTick);
    if (ret == 1) {
        return LOS_ERRNO_TICK_PER_SEC_TOO_SMALL;
    }

    return LOS_OK;
}

1.3 Tick中断处理函数OsTickHandler()

文件kernel\src\los_tick.c定义的函数VOID OsTickHandler(VOID),是时间管理模块中执行最频繁的函数,每当Tick中断发生时就会调用该函数。我们分析下该函数的源码,⑴处如果开启宏LOSCFG_BASE_CORE_TICK_HW_TIME,会调用定制的tick处理函数platform_tick_handler(),默认不开启。⑵处会更新全局变量g_ullTickCount,⑶处如果开启宏LOSCFG_BASE_CORE_TIMESLICE,会检查当前运行任务的时间片,在后续任务模块会详细分析下函数OsTimesliceCheck()。⑷处会遍历任务的排序链表,检查是否有超时的任务。⑸处如果支持定时器特性,会检查定时器是否超时。

源码如下:

LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
#if (LOSCFG_BASE_CORE_TICK_HW_TIME == 1)
⑴  platform_tick_handler();
#endif

⑵  g_ullTickCount++;

#if (LOSCFG_BASE_CORE_TIMESLICE == 1)
⑶  OsTimesliceCheck();
#endif

⑷   OsTaskScan();  // task timeout scan

#if (LOSCFG_BASE_CORE_SWTMR == 1)
⑸  (VOID)OsSwtmrScan();
#endif
}

2、LiteOS内核时间管理常用操作

时间管理提供下面几种功能,时间转换、时间统计等,这些函数定义在文件kernel\src\los_tick.c,我们剖析下这些操作的源代码实现。

2.1 时间转换操作

2.1.1 毫秒转换成Tick

函数UINT32 LOS_MS2Tick(UINT32 millisec)把输入参数毫秒数UINT32 millisec可以转化为Tick数目。代码中OS_SYS_MS_PER_SECOND,即1秒等于1000毫秒。时间转换也比较简单,知道一秒多少Tick,除以OS_SYS_MS_PER_SECOND,得出1毫秒多少Tick,然后乘以millisec,计算出Tick数目的结果值并返回。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
{
    if (millisec == OS_NULL_INT) {
        return OS_NULL_INT;
    }

    return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND;
}
2.1.2 Tick转化为毫秒

函数UINT32 LOS_Tick2MS(UINT32 tick)把输入参数Tick数目转换为毫秒数。时间转换也比较简单,ticks数目除以每秒多少Tick数值LOSCFG_BASE_CORE_TICK_PER_SECOND,计算出多少秒,然后转换成毫秒,计算出结果值并返回。

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 ticks)
{
    return ((UINT64)ticks * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
2.1.3 Cycle数目转化为毫秒

介绍转换函数之前,先看下一个CpuTick结构体,结构体比较简单,就2个成员,分别表示一个UINT64类型数据的高、低32位数值。

typedef struct tagCpuTick {
    UINT32 cntHi; /* < 一个64位数值的高32位 */
    UINT32 cntLo; /* < 一个64位数值的低32位 */
} CpuTick;

继续看转换函数OsCpuTick2MS(),它可以把CpuTick类型表示的cycle数目转换为对应的毫秒数,输出毫秒数据的高、低32位数值。看下具体的代码,⑴处校验参数是否为空指针,⑵处检查系统时钟是否配置。⑶处把CpuTick结构体表示的cycle数目转化为UINT64类型数据。⑷处进行数值计算,(DOUBLE)g_sysClock / OS_SYS_MS_PER_SECOND得到每毫秒多少个cycle数,然后和tmpCpuTick做除法运算,得到cycle数目对应的毫秒数目。⑸处把DOUBLE类型转换为UINT64类型,然后执行⑹,分别把结果数值的高、低64位赋值给*msLo*msHi

LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2MS(CpuTick *cpuTick, UINT32 *msHi, UINT32 *msLo)
{
    UINT64 tmpCpuTick;
    DOUBLE temp;

⑴  if ((cpuTick == NULL) || (msHi == NULL) || (msLo == NULL)) {
        return LOS_ERRNO_SYS_PTR_NULL;
    }

⑵  if (g_sysClock == 0) {
        return LOS_ERRNO_SYS_CLOCK_INVALID;
    }
⑶  tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo;
⑷  temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_MS_PER_SECOND);

    tmpCpuTick = (UINT64)temp;

    *msLo = (UINT32)tmpCpuTick;
    *msHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT);

    return LOS_OK;
}
2.1.4 Cycle数目转化为微秒

转换函数OsCpuTick2US(),它可以把CpuTick类型表示的cycle数目转换为对应的毫秒数,输出毫秒数据的高、低32位数值。该函数和OsCpuTick2MS()类似,自行阅读即可。

LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2US(CpuTick *cpuTick, UINT32 *usHi, UINT32 *usLo)
{
    UINT64 tmpCpuTick;
    DOUBLE temp;

    if ((cpuTick == NULL) || (usHi == NULL) || (usLo == NULL)) {
        return LOS_ERRNO_SYS_PTR_NULL;
    }

    if (g_sysClock == 0) {
        return LOS_ERRNO_SYS_CLOCK_INVALID;
    }
    tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo;
    temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_US_PER_SECOND);

    tmpCpuTick = (UINT64)temp;

    *usLo = (UINT32)tmpCpuTick;
    *usHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT);

    return LOS_OK;
}

2.2 时间统计操作

2.2.1 获取每个Tick等于多少Cycle数

函数UINT32 LOS_CyclePerTickGet(VOID)计算1个tick等于多少cycleg_sysClock系统时钟表示1秒多少cycleLOSCFG_BASE_CORE_TICK_PER_SECOND一秒多少tick,相除计算出1 tick多少cycle数,即g_cyclesPerTick = g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND

LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
{
    return g_cyclesPerTick;
}
2.2.2 获取自系统启动以来的Tick数

UINT64 LOS_TickCountGet(VOID)函数计算自系统启动以来的Tick中断的次数。需要注意,在关中断的情况下不进行计数,不能作为准确时间使用。每次Tick中断发生时,在函数VOID OsTickHandler(VOID)中会更新g_ullTickCount数据。

LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
{
    return g_ullTickCount;
}
2.2.3 获取系统时钟

UINT32 LOS_SysClockGet(VOID)函数获取配置的系统时钟。

UINT32 LOS_SysClockGet(VOID)
{
    return g_sysClock;
}
2.2.4 获取系统启动以来的Cycle数

函数VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo)定义在文件kernel\arch\arm\cortex-m7\gcc\los_timer.c中,该函数获取系统启动以来的Cycle数。返回结果按高、低32位的无符号数值UINT32 *cntHi, UINT32 *cntLo分别返回。

我们看下该函数的源码。先关中断,然后⑴处获取启动启动以来的Tick数目。⑵处通过读取当前值寄存器SysTick Current Value Register,获取hwCycle。⑶处表示中断控制和状态寄存器Interrupt Control and State Register的第TICK_CHECK位为1时,表示挂起systick中断,tick没有计数,需要加1校准。⑷处根据swTickg_cyclesPerTickhwCycle计算出自系统启动以来的Cycle数。⑸处获取Cycle数的高、低32位的无符号数值,然后开中断、返回。

LITE_OS_SEC_TEXT_MINOR VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo)
{
    UINT64 swTick;
    UINT64 cycle;
    UINT32 hwCycle;
    UINTPTR intSave;

    intSave = LOS_IntLock();

⑴  swTick = g_ullTickCount;
⑵  hwCycle = SysTick->VAL;

⑶  if ((SCB->ICSR & TICK_CHECK) != 0) {
        hwCycle = SysTick->VAL;
        swTick++;
    }

⑷  cycle = (((swTick) * g_cyclesPerTick) + (g_cyclesPerTick - hwCycle));

⑸  *cntHi = cycle >> SHIFT_32_BIT;
    *cntLo = cycle & CYCLE_CHECK;

    LOS_IntRestore(intSave);

    return;
}

小结

本文带领大家一起剖析了鸿蒙轻内核的时间管理模块的源代码。时间管理模块为任务调度提供必要的时钟节拍,会向应用程序提供所有和时间有关的服务,如时间转换、统计、延迟功能。后续也会陆续推出更多的分享文章,敬请期待,也欢迎大家分享学习、使用鸿蒙轻内核的心得,有任何问题、建议,都可以留言给我们: https://gitee.com/openharmony/kernel_liteos_m/issues 。为了更容易找到鸿蒙轻内核代码仓,建议访问 https://gitee.com/openharmony/kernel_liteos_m,关注Watch、点赞Star、并Fork到自己账户下,谢谢。

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AMD MI300X vs Nvidia H100/H200:AI计算领域的新一轮较量

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;计算引擎的性能竞赛也愈演愈烈。近期&#xff0c;MLCommons发布的最新AI训练和推理基准测试结果&#xff0c;他们构建了一套 MLPerf AI 训练和推理基准&#xff0c;将AMD的Instinct“Antares”MI300X GPU与Nv…

远端ide ,vscode ,python 开发环境, 有些还有一建生成chatgpt功能,支持gpu功能

现在智能化的AI工具&#xff0c;可以实现智能聊天、文本生成、语言翻译等多种功能。 博主归纳总结了6个好用免费的AI工具网站&#xff0c;供大家参考。 ## 1&#xff0c;insCode 网址&#xff1a; https://inscode.csdn.net/ 简介&#xff1a; InsCode 是一个以“灵感”&am…

SQL-多表查询

1、多表关系 一对多、多对一&#xff1a;在多的一方建立外键&#xff0c;指向一的一方。 多对多&#xff1a;至少两个外键&#xff0c;通过中间表维护。 一对一 2、多表查询概述 3、内连接 4、外连接 5、自连接 6、联合查询 7、子查询 8、多表查询案例 # 1、多表关系 #…

Day 3 - 5 :线性表 — 单链表

存储结构 将线性表中的各元素分布在存储器的不同存储块&#xff0c;称为结点。 结点的data域存放数据元素ai&#xff0c;而next域是一个指针&#xff0c;指向ai的直接后继ai1所在的结点。 如果要删除a1&#xff0c;只要修改a1前手元素指针的指向即可。 例如&#xff1a;需要找到…

苏宁易购发布公告 管理层提前超额完成增持计划

9月5日&#xff0c;苏宁易购发布公告称&#xff0c;包括苏宁易购总裁任峻在内的公司部分董事、高级管理人员和核心业务骨干已通过集中竞价交易方式累计增持公司股份4,067,000股&#xff0c;合计增持金额511.95万元。高管增持计划的完成&#xff0c;展现了管理层对公司未来发展的…

【华为】测试工程师面试题汇总,你可知道华为的高薪技术岗有多香~

华为一直是求职者重点投递的热门企业&#xff0c;面对丰厚的薪资福利&#xff0c;无数985、211的学子挤破脑袋都想占据一席之地。 华为2021年发放工资、薪金及其他福利方面的费用达1371亿元人民币&#xff0c;按华为19.5万员工计算&#xff0c;华为员工人均年薪为70.3万&#…

如何在Mac电脑上本地部署Stable Diffusion:详细教程(webUI)

Stable Diffusion是一款强大的AI生成图像模型&#xff0c;它可以基于文本描述生成高质量的图像。对于想要在本地运行此模型的用户来说&#xff0c;使用Mac电脑部署Stable Diffusion是一个非常吸引人的选择&#xff0c;特别是对于M1或M2芯片的用户。本文将详细介绍如何在Mac上本…

计算机毕业设计选题推荐-企业会议室管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

CSS3换装达人原理

引言 换装或者是换皮肤是常见的行为&#xff0c;我们可以先看下效果&#xff1a; 选择不同的颜色&#xff0c;就可以秒变人物服装的颜色&#xff0c;原理其实非常简单 实现步骤 主要分为三步&#xff0c;即素材的提供、布局样式、动态控制 图片提供 提供两张图片&#xf…

如何防止常见的Web应用安全漏洞!

Web应用的广泛使用伴随着各种安全威胁。近年来&#xff0c;许多企业因忽视Web应用的安全性而遭受重大损失。本文将介绍几种常见的Web应用安全漏洞&#xff0c;并提供具体的防护方案和实战演练。 常见的Web应用安全漏洞 1. SQL注入 - 简介&#xff1a;攻击者通过在输入字段中插…

C语言刷题日记(附详解)(4)

一、选填部分 第一题: 下面四个选项中&#xff0c;均是不合法的用户标识符的选项是( ) A. A P_0 do B. float la0 _A C. b-a sizeof int D. b_a temp _123 思路提示&#xff1a;题中所问的是"不合法"的"用户标识符"&#xff0c;要记得&#xff0c;C…

上手一个RGBD深度相机:从原理到实践--ROS noetic+Astra S(上):解读深度测距原理和内外参推导

前言 最近在做项目的时候&#xff0c;项目组丢给了我一个深度相机&#xff0c;今天我们来尝试上手一个实体深度相机。 本教程设计基础相机的原理&#xff0c;使用&#xff0c;标定&#xff0c;和读取。(注&#xff1a;本教程默认大家有ROS1基础&#xff0c;故不对程序进行详细…

SpringCloud Hystrix的解析

概述 Hystrix 为 微服务架构提供了一整套服务隔离、服务熔断和服务降级的解决方案。它是熔断器的一种实现&#xff0c;主要用于解决微服务架构的高可用及服务雪崩等问题 Hystrix 的特性如下&#xff1a; 服务熔断&#xff1a;Hystrix 熔断器就像家中的安全阀一样&#xff0c…

哪款宠物空气净化器能更好的清理浮毛?希喂、352、IAM测评分享

家里这三只可爱的小猫咪&#xff0c;已然成为了我们生活中不可或缺的家庭成员&#xff0c;陪伴我们度过了说长不长说短不短的五年时光。时常庆幸自己当年选择养它们&#xff0c;在我失落的时候总能给我安慰&#xff0c;治愈我多时。 但这个温馨的背后也有一点小烦恼&#xff0…

A02、Java编程性能调优(02)

1、Stream如何提高遍历集合效率 1.1、什么是Stream 现在很多大数据量系统中都存在分表分库的情况。例如&#xff0c;电商系统中的订单表&#xff0c;常常使用用户 ID 的 Hash 值来实现分表分库&#xff0c;这样是为了减少单个表的数据量&#xff0c;优化用户查询订单的速度。 …

VBA数据库解决方案第十四讲:如何在数据库中动态删除和建立数据表

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…

macos MacPort 包管理工具安装和使用

在macos v10.15版本中, xz, python等软件无法使用brew安装, 原因是brew对于旧版本的macos不再支持, 但是我们可以使用另外一个macos下的包管理工具来安装brew无法安装的软件, macport 是一个和brew类似的macos下的一个非常优秀的软件包安装管理工具. MacPort安装前提条件 安…

001集——CAD—C#二次开发入门——开发环境基本设置

CAD C#二次开发首先需要搭建一个舒服的开发环境&#xff0c;软件安装后&#xff0c;需要修改相关设置。本文为保姆级入门搭建开发环境教程&#xff0c;默认已成功安装vs和cad 。 第一步&#xff1a;创建类库 第二步&#xff1a;进行相关设置&#xff0c;如图&#xff1a; 下一…

【OpenWrt(2)】编译OpenWrt 的SDK,以linksys e8450 的MT7622 CPU为例

资源 参考 https://downloads.openwrt.org/releases/ 文章目录 资源依赖下载 SDK查询 CPU 信号 解压使用 feed 编译后台运行 依赖 apt-get update apt-get install subversion build-essential libncurses5-dev zlib1g-dev gawk git ccache gettext libssl-dev xsltproc wget…

一万字❤ 计算机网络知识✔ 带你全面了解网络原理【详解 + 代码演示 + 图解】(期末考试、面试必备)

文章目录 1. 网络基础1.1 局域网1.2 广域网1.3 IP 地址1.4 端口号1.5 协议1.6 协议分层1.7 网络模型1.7.1 OSI 七层模型1.7.2 TCP/IP 五层模型 2. 网络编程2.1 TCP 和 UDP 的区别2.2 UDP的 Socket API2.2.1 DatagramSocket2.2.1.1 构造方法2.2.1.2 主要方法 2.2.2 DatagramPack…