文章目录
- 密码系统设计
- 第九周预习报告
- 学习内容
- AI 对学习内容的总结(1分)
- 要求
- 总结
- 对 AI 总结的反思与补充(2分)
- 要求
- 反思与补充
- 学习思维导图(2分)
- 要求
- 思维导图
- 基于 AI 的学习(2分)
- 要求
- 学习内容
- 学习实践过程遇到的问题与解决方式(AI 驱动,优先使用AI工具解决问题)(2分)
- 作业提交要求(1分)
密码系统设计
推荐VSCode中安装Markdown插件和markdown pdf 插件完成作业
第九周预习报告
学习内容
- Head First C 嗨翻 C 语言 第9章
- 课程 mindmap
AI 对学习内容的总结(1分)
要求
- 让AI(kimi,元宝等)阅读学习内容并进行总结,教材内容可以使用微信读书或者云班课电子教材
总结
第九章主要介绍了进程和系统调用的概念,以及如何在C程序中使用这些概念来创建和控制进程。以下是对第九章学习内容的总结:
-
系统调用(System Calls):
- 系统调用是C程序与操作系统内核交互的接口,用于执行如文件操作、进程控制等任务。
system()
函数是一个常用的系统调用,它允许程序执行一个命令字符串,就像在命令行中输入一样。
-
进程控制:
- 进程是程序运行的实例,每个进程都有一个唯一的进程标识符(PID)。
fork()
函数用于创建一个新的进程,称为子进程,它是当前进程的副本。exec()
系列函数用于在当前进程中执行一个新的程序,替换当前的进程映像。
-
fork()
和exec()
的组合使用:- 通过
fork()
创建子进程后,可以在子进程中调用exec()
来运行新的程序,而父进程则可以继续执行其他任务或等待子进程完成。
- 通过
-
进程间通信(Interprocess Communication, IPC):
- 进程间通信允许进程之间共享数据或相互协调工作。
- 可以通过文件描述符、管道(pipes)等方式实现进程间的通信。
-
文件描述符和重定向:
- 每个打开的文件或数据流都会被分配一个文件描述符,这是一个代表数据流的数字。
- 可以通过重定向操作符(
>
和<
)将标准输入输出流重定向到文件或其他数据流。
-
waitpid()
函数:- 父进程可以使用
waitpid()
函数等待子进程结束,确保在子进程完成其任务之前父进程不会退出。
- 父进程可以使用
-
错误处理:
- 系统调用失败时会遵循一些“黄金规则”,包括设置全局变量
errno
以指示错误类型,并返回-1。 strerror()
函数可以将错误编号转换为可读的错误消息。
- 系统调用失败时会遵循一些“黄金规则”,包括设置全局变量
-
exit()
函数:exit()
函数用于立即终止程序,它接受一个整型参数作为退出状态码。
第九章的内容强调了进程管理的重要性,以及如何在C程序中有效地使用系统调用来创建和管理进程。这些概念对于编写能够执行复杂任务的程序至关重要,因为它们允许程序并行执行多个任务,并提供了一种协调不同程序执行部分的方法。
对 AI 总结的反思与补充(2分)
要求
- AI总结的问题
- 自己的补充
反思与补充
总结存在以下问题和需要补充的地方:
-
细节深度:总结可能没有涵盖第九章中的所有细节和示例,特别是关于
fork()
和exec()
函数的具体使用案例,以及它们在实际编程中的应用。 -
错误处理:虽然提到了
errno
和strerror()
,但没有详细解释如何有效地使用这些工具来进行错误处理,以及如何在实际代码中实现错误检查和异常处理。 -
安全性问题:在使用
system()
函数时,提到了注入攻击的风险,但没有深入讨论如何安全地使用系统调用,以及如何避免潜在的安全漏洞。 -
fork()
和exec()
的替代方案:没有提到在不支持fork()
的系统(如Windows)上的替代方案,例如CreateProcess()
函数。 -
进程间通信(IPC)机制:除了文件描述符和重定向,还有其他IPC机制,如信号、消息队列、共享内存等,这些在总结中没有提及。
-
实际应用场景:总结中缺乏对进程控制和IPC在实际应用中如何使用的讨论,例如在网络编程、多线程应用或并发处理中。
-
代码示例:总结中没有包含实际的代码示例,这些示例可以帮助更好地理解和记忆第九章的概念。
-
waitpid()
的详细用法:waitpid()
函数的用法和选项没有详细解释,这个函数在处理多个子进程时非常有用。 -
资源管理:在创建进程时,资源管理(如内存和文件描述符)是一个重要的考虑因素,但总结中没有提到如何有效地管理这些资源。
-
操作系统差异:不同操作系统之间在进程管理和系统调用方面存在差异,总结中没有强调这些差异,以及如何在跨平台编程中处理这些差异。
反思:在总结技术章节时,应该更加注重概念的应用和实际操作,以及安全性和最佳实践。此外,应该提供更多的上下文和实际代码示例,以便读者能够更好地理解和应用这些概念。最后,应该考虑到不同操作系统和环境之间的差异,并提供相应的指导。
学习思维导图(2分)
要求
- Mermaid 代码与截图(参考Mermaid MindMap语法)或者提交思维导图链接(如果使用线上编辑器,推荐processon,xmind,…)
思维导图
下面是个简单mermaid的思维导图,你可以根据你自己的需求修改
mindmaproot((密码系统设计第一周))Head First C第九章graph TDA[第九章总结] --> B[系统调用]A --> C[进程控制]A --> D[进程间通信(IPC)]A --> E[错误处理]A --> F[exit()函数]A --> G[安全问题]B --> B1[system()函数]B --> B2[exec()系列函数]C --> C1[进程和PID]C --> C2[fork()函数]C --> C3[waitpid()函数]D --> D1[文件描述符]D --> D2[重定向]D --> D3[管道(pipes)]D --> D4[其他IPC机制]E --> E1[errno]E --> E2[strerror()]E --> E3[错误检查和异常处理]F --> F1[终止程序]F --> F2[退出状态码]G --> G1[注入攻击]G --> G2[安全使用系统调用]课件网络空间安全密码与密码系统法律法规与标准密码应用与密评实践gitee(github)opensslgmssl
上面mermaid实际效果,vscode中可以预览:
基于 AI 的学习(2分)
要求
- 至少找到自己理解不是太好 2 个概念,让 AI 对自己进行苏格拉底提问
- 参考下面提示语或者使用 AI Agent
提示词:“我在学习XXX知识点,请你以苏格拉底的方式对我进行提问,一次一个问题”
- 核心是要求AI工具:“请你以苏格拉底的方式对我进行提问”
- 然后AI工具就会给你提问,如果不知道问题的答案,可以反问AI:“你的理解(回答)是什么?”
- 如果你觉得差不多了,可以先问问AI工具:“针对我XXX知识点,我理解了吗?”
- AI工具会给出它的判断,如果你也觉得自己想清楚了,可以最后问AI工具:“我的回答结束了,请对我的回答进行评价总结”,让它帮你总结一下。
学习内容
me
我在学习进程和系统调用知识点,请你以苏格拉底的方式对我进行提问,一次一个问题
ai
当然可以,让我们开始吧。1. 你能告诉我什么是系统调用吗?它是如何与操作系统内核交互的?
me
系统调用是操作系统内核提供的一组用于实现各种系统功能的子程序或过程,这些子程序或过程通过特定的接口供用户程序调用。它是操作系统提供给用户程序的唯一接口,允许用户程序在运行时请求操作系统执行特定的操作,如文件操作、进程控制、进程间通信、设备管理等。系统调用类似于一个黑箱子,对用户屏蔽了操作系统的具体实现细节,只提供相关的功能接口。
系统调用与操作系统内核的交互过程通常涉及以下几个关键步骤:
1. 用户态程序发起系统调用:
- 用户态程序通过特定的方式(如使用库函数封装的系统调用接口)发起系统调用请求。这些库函数内部会准备相应的参数,并通过某种机制(如软中断)将控制权转移给操作系统内核。
2. 陷入内核态:
- 当用户态程序执行系统调用指令时,CPU会检测到这一指令,并将当前程序的执行状态从用户态切换到内核态。这种切换通常是通过硬件中断机制实现的,以确保用户态程序不能直接访问内核态的资源。
3. 执行系统调用处理程序:
- 在内核态下,CPU会跳转到系统调用处理程序的入口点。这个处理程序会根据系统调用的编号(也称为系统调用号)查找相应的系统调用服务例程并执行。系统调用号通常作为系统调用指令的一个参数传递给内核。
4. 内核处理系统调用请求:
- 系统调用服务例程会执行相应的内核函数来完成用户请求的操作。这些操作可能涉及对硬件设备的访问、对进程状态的修改、对文件系统的操作等。内核在处理系统调用请求时拥有完全的权限和资源访问能力。
5. 返回用户态并传递结果:
- 当系统调用服务例程执行完毕后,它会将处理结果(如果有的话)保存在特定的位置(如CPU的寄存器中),并通过某种机制将控制权返回给用户态程序。用户态程序可以通过检查这些位置来获取系统调用的处理结果。
6. 恢复用户态程序的执行:
- 在返回用户态之前,内核会恢复用户态程序的上下文环境(如CPU寄存器状态、内存堆栈等),以确保用户态程序能够继续从系统调用指令之后的下一条指令开始执行。
需要注意的是,不同操作系统和硬件平台上的系统调用实现机制可能有所不同。例如,在Linux操作系统中,系统调用通常通过软中断指令(如x86架构下的int 0x80
或syscall指令)触发,并通过系统调用表来查找相应的服务例程。而在Windows操作系统中,系统调用的实现机制则有所不同。
此外,随着操作系统和硬件技术的发展,系统调用的实现方式也在不断演进。例如,现代操作系统中广泛采用了虚拟内存管理技术来隔离用户态和内核态的地址空间,以确保系统的安全性和稳定性。同时,为了提高系统调用的性能,一些操作系统还采用了快速系统调用(fast
syscall)等技术来减少系统调用的开销。
ai
很好,你已经详细解释了系统调用是什么以及它们如何与操作系统内核交互。现在,让我们深入一点:2. 系统调用和库函数之间有什么关系?为什么我们通常不直接调用系统调用,而是通过库函数来实现?
me
系统调用和库函数之间存在密切的关系,但它们在操作系统中的作用和角色有所不同。以下是关于这两者之间关系的详细解答,以及我们通常不直接调用系统调用的原因。 系统调用和库函数的关系1. 定义与角色 - 系统调用:是操作系统内核提供的一组函数接口,允许运行在用户态的程序请求内核态的服务。它们是操作系统与用户程序之间的桥梁,用于执行底层硬件操作、进程管理、文件操作等系统级任务。 - 库函数:是语言或应用程序的一部分,通常位于更高级别的抽象层。它们为程序员提供了执行常见编程任务的接口,如字符串操作、数学运算、文件I/O等。库函数可以运行在用户空间中,无需直接与系统资源交互。 2. 联系- 许多库函数内部会调用系统调用来实现其功能。例如,在C语言中,`fopen`、`fclose`、`fwrite`等文件操作函数底层都是通过`open`、`close`、`write`等系统调用来实现的。这种封装使得程序员无需直接与系统调用打交道,从而简化了编程工作。 3. 区别- 执行空间:系统调用运行在内核空间中,而库函数通常运行在用户空间中。 - 可移植性:由于库函数提供了更高层次的抽象,因此它们通常比系统调用更可移植。不同的操作系统可能具有不同的系统调用接口,但相同的库函数接口在不同平台上可能具有相似的行为。 - 性能:直接调用系统调用通常具有更高的性能,因为减少了中间层的开销。然而,过度使用系统调用可能会导致性能下降,因为每次系统调用都涉及从用户模式切换到内核模式的过程。 为什么我们通常不直接调用系统调用 1. 简化编程:库函数提供了更简洁、更易于理解的接口,隐藏了底层系统调用的复杂性。程序员无需了解系统调用的具体实现细节,就可以轻松地完成常见的编程任务。 2. 提高可移植性:库函数通常具有更好的可移植性,因为它们提供了跨平台的抽象层。相比之下,系统调用更依赖于特定的操作系统和硬件平台。 3. 优化性能:虽然直接调用系统调用在理论上具有更高的性能,但库函数通过封装和优化系统调用的使用,可以在大多数情况下提供接近甚至更优的性能。例如,库函数可能会利用缓冲区技术来减少系统调用的次数,从而提高文件I/O操作的性能。 4. 安全性:库函数通常提供了额外的安全性检查,以防止非法或错误的系统调用请求。这些检查有助于减少系统漏洞和潜在的安全风险。 综上所述,系统调用和库函数在操作系统中扮演着不同的角色,但它们之间紧密相连、相辅相成。我们通常不直接调用系统调用,而是通过库函数来实现所需的功能,这主要是出于简化编程、提高可移植性、优化性能和增强安全性的考虑。
ai
非常好,你已经很好地解释了系统调用和库函数之间的关系以及为什么我们通常不直接调用系统调用。现在,让我们继续探讨:3. 在C语言中,`fork()`系统调用做了什么?它如何影响程序的执行流程?
me
在C语言中,`fork()` 是一个非常重要的系统调用,它用于创建一个新的进程,称为子进程。这个新进程是调用 `fork()` 的父进程的几乎完全相同的副本,但有一些关键的区别。以下是 `fork()` 系统调用的具体行为以及它对程序执行流程的影响:`fork()` 的行为 1. 创建新进程:`fork()` 创建一个新的进程,该进程是调用它的父进程的副本。新创建的进程称为子进程,而调用 `fork()` 的进程称为父进程。 2. 复制进程状态:子进程会继承父进程的大部分状态,包括进程地址空间、文件描述符、当前工作目录、进程组、会话等。但是,有一些状态是独立的,比如进程ID(PID)、父进程ID(PPID)、进程执行顺序等。 3. 返回值:`fork()` 在父进程和子进程中的返回值是不同的。在父进程中,`fork()` 返回新创建的子进程的PID。在子进程中,`fork()` 返回0。如果 `fork()` 调用失败,它将在父进程中返回 -1,并设置 `errno` 以指示错误原因。 对程序执行流程的影响 1. 并发执行:由于子进程和父进程是独立的进程,它们会并发地执行。操作系统调度器负责在多个进程之间切换,以给它们分配CPU时间。 2. 共享与独立:虽然子进程继承了父进程的大部分状态,但它们之间的地址空间是独立的(除了使用写时复制机制的共享内存区域)。这意味着父进程和子进程可以独立地修改它们的内存,而不会影响彼此。然而,文件描述符是共享的,所以它们可以共同操作同一个文件或管道。 3. 执行顺序的不确定性:由于并发执行,父进程和子进程的执行顺序是不确定的。这取决于操作系统的调度策略和其他进程的活动情况。 4. 资源管理:程序员需要注意管理进程间共享的资源,比如文件、管道、内存等。为了避免竞态条件和资源泄露,通常需要使用同步机制(如信号量、互斥锁)和适当的资源管理策略。 5. 进程终止:当父进程或子进程执行完毕时,它们可以调用 `exit()` 系统调用来终止自己。如果父进程终止了,子进程通常会继续执行,直到它们自己也终止。然而,如果子进程终止了,父进程应该调用 `wait()` 或 `waitpid()` 系统调用来获取子进程的终止状态,以避免产生僵尸进程。 综上所述,`fork()` 系统调用在C语言中用于创建一个新的进程,并且对程序的执行流程产生重大影响。程序员需要仔细管理进程间的共享资源,并处理并发执行带来的不确定性。
学习实践过程遇到的问题与解决方式(AI 驱动,优先使用AI工具解决问题)(2分)
- 理解不同的IPC机制(如管道、消息队列、共享内存)及其使用场景可能具有挑战性。
解决方式: 阅读关于IPC机制的基础教材或在线资源,了解管道、消息队列、共享内存等概念的定义、特点和工作原理。
- 学习如何安全地使用系统调用,防止注入攻击和其他安全漏洞。
解决方式: 学习不同类型的注入攻击,如SQL注入、命令行注入等,了解它们是如何利用系统调用的漏洞来执行恶意代码的。
确保程序以最低必要权限运行,减少攻击者利用系统调用造成的损害。
正确处理系统调用失败的情况,避免泄露敏感信息。
作业提交要求(1分)
- 提交Markdown 文件,文档命名“学号姓名《密码系统设计》.md”
- 提交Markdown 文件转为 PDF,文档命名“学号姓名《密码系统设计》第 X 周.pdf”
- 提交代码托管链接(可选):学号姓名 gitee(github) 链接
- 内容质量高有加分