文章目录
- 密码系统设计
- 第九周预习报告
- 学习内容
- AI 对学习内容的总结(1分)
- 要求
- 总结
- 对 AI 总结的反思与补充(2分)
- 反思与补充
- 补充内容
- 反思
- 学习思维导图(2分)
- 要求
- 思维导图
- 代码
- 导图
- 基于 AI 的学习(2分)
- 要求
- 学习内容
- 学习实践过程遇到的问题与解决方式(AI 驱动,优先使用AI工具解决问题)(2分)
- 作业提交要求(1分)
- 参考资料
密码系统设计
第九周预习报告
学习内容
- Head First C 嗨翻 C 语言 第9章
- 课程 mindmap
AI 对学习内容的总结(1分)
要求
- 让AI(kimi,元宝等)阅读学习内容并进行总结,教材内容可以使用微信读书或者云班课电子教材
总结
这份文件是关于如何在C语言程序中使用系统调用来创建和管理进程的教程。以下是对文件内容的总结:
-
系统调用(System Calls):
- 系统调用是C程序与操作系统内核通信的方式,用于访问硬件资源。
- 标准库中的大多数函数都依赖于系统调用。
system()
函数是一个简单的系统调用,它接受一个字符串参数并在命令行中执行,类似于在命令行中输入命令。
-
使用
system()
函数:system()
可以用来快速原型开发,避免编写大量C代码。- 但是,
system()
函数存在安全隐患,因为它会执行任何传入的命令,可能会导致安全漏洞。
-
exec()
函数族:exec()
函数提供了比system()
更多的控制,它们可以精确地告诉操作系统要运行的程序。exec()
函数会替换当前进程,而不是创建一个新进程。- 有多种
exec()
函数,包括execl()
,execlp()
,execle()
,execv()
,execvp()
,execve()
,它们的区别在于参数的形式和是否搜索PATH环境变量。
-
环境变量:
- 每个进程都有一组环境变量,可以通过
getenv()
函数读取。 - 使用
execle()
时,可以传递一个环境变量数组。
- 每个进程都有一组环境变量,可以通过
-
错误处理:
- 大多数系统调用失败时会遵循一套规则,包括设置全局变量
errno
并返回-1。 strerror()
函数可以将错误代码转换为可读的错误消息。
- 大多数系统调用失败时会遵循一套规则,包括设置全局变量
-
fork()
系统调用:fork()
创建当前进程的一个副本,称为子进程。- 原始进程称为父进程,新创建的副本称为子进程。
fork()
之后,父进程和子进程将拥有不同的进程标识符(PID)。
-
结合
fork()
和exec()
使用:- 通过在子进程中调用
exec()
,可以让父进程继续执行其他任务,而子进程则运行新的程序。 - 这种方法可以同时运行多个进程,提高程序性能。
- 通过在子进程中调用
-
CreateProcess()
:- 在Windows系统中,没有
fork()
系统调用,但可以使用CreateProcess()
函数,它类似于增强版的system()
。
- 在Windows系统中,没有
-
多进程输出:
- 操作系统确保每个进程的输出不会混淆。
这份文件通过示例代码和解释,教授了如何在C语言程序中使用系统调用来创建和管理进程,以及如何利用fork()
和exec()
函数来提高程序的并发性和性能。同时,也强调了在使用这些系统调用时需要注意的安全和错误处理问题。
对 AI 总结的反思与补充(2分)
反思与补充
补充内容
system()
函数示例补充:- 在介绍
system()
函数时,文中给出了多个示例,如system("dir D:")
(在Windows系统中打印D盘内容)、system("gedit")
(在Linux系统中启动编辑器)、system("say 'End of line'")
(在Mac系统中朗读文本),这些示例直观地展示了system()
函数在不同操作系统下执行不同命令的功能,进一步强调了其便利性和跨平台性,但同时也暗示了其潜在风险,因为它直接执行输入的命令字符串,若字符串被恶意构造,可能会引发安全问题。 - 文中通过
guard_log
程序详细说明了system()
函数的使用场景,它将用户输入的评论与时间戳组合成命令字符串,然后使用system()
函数调用echo
命令将其添加到日志文件中。这个示例不仅展示了如何在实际程序中运用system()
函数处理文件操作,还引出了后续关于system()
函数安全性和局限性的讨论,即如果用户输入恶意命令,可能会导致系统执行任意代码。
- 在介绍
exec()
函数族详细说明:- 对于
exec()
函数族的介绍非常全面,详细阐述了列表函数(execl()
、execlp()
、execle()
)和数组函数(execv()
、execvp()
、execve()
)的参数形式和区别。例如,列表函数接受命令行参数作为参数列表,且最后一个参数必须为NULL
,以表示参数结束;而数组函数则适用于命令行参数已存储在数组中的情况。同时,指出execlp()
和execvp()
会在PATH
环境变量中搜索程序,这为在不同环境下灵活运行程序提供了便利。 - 通过
diner_info
程序示例,清晰地展示了execle()
函数如何设置命令行参数和环境变量,并替换当前进程执行新程序。在这个示例中,创建了一个包含特定环境变量(JUICE=peach and apple
)的数组,并将其传递给execle()
函数,同时指定了要执行的程序(diner_info
)及其参数,生动地体现了exec()
函数族在控制程序执行环境和参数方面的强大功能。
- 对于
- 错误处理机制深入:
- 在错误处理部分,以
execle()
函数调用为例,深入解释了如何判断系统调用是否失败。如果exec()
函数调用成功,当前程序将停止运行,因此若在调用exec()
函数后还有代码执行,则说明调用出现问题。这种判断方式简单而直接,为程序员在实际编程中检测exec()
函数调用的正确性提供了明确的方法。 - 文中详细介绍了
errno
变量和strerror()
函数的用法。errno
是一个全局变量,定义在errno.h
头文件中,包含了一系列标准错误值,如EPERM
(操作不被允许)、ENOENT
(文件或目录不存在)等。strerror()
函数则用于将errno
中的错误代码转换为可读的错误消息,方便程序员在程序中输出错误信息,以便调试和排查问题。例如,当系统找不到要运行的程序并设置errno
为ENOENT
时,strerror(errno)
将返回No such file or directory
,使错误原因一目了然。
- 在错误处理部分,以
fork()
系统调用与进程关系:- 对
fork()
系统调用的解释深入到进程层面,详细说明了它如何创建当前进程的副本,包括副本与原始进程在代码执行位置、变量值等方面的一致性,以及唯一的区别——进程标识符(PID)。这种详细的解释有助于理解进程复制的本质,以及后续如何利用fork()
创建子进程来实现并发执行。 - 通过
newshound
程序的逐步改进过程,生动地展示了fork()
和exec()
函数结合使用的实际效果。首先,分析了原始newshound
程序中仅使用execle()
函数导致只能运行一次rssgossip.py
脚本的问题,原因是exec()
函数会替换当前进程,使得程序在第一次调用execle()
后就终止。然后,引入fork()
函数,详细描述了如何通过fork()
创建子进程,在子进程中调用exec()
函数来运行rssgossip.py
脚本,而父进程则可以继续循环处理其他RSS源,从而实现同时运行多个进程,提高程序性能,这个过程清晰地展示了fork()+exec()
模式在实际多进程编程中的应用场景和优势。
- 对
反思
- 安全性强调的重要性:文中多次强调了系统调用在安全性方面的问题,如
system()
函数可能被注入恶意命令导致安全漏洞,这是非常关键的一点。在实际编程中,安全问题往往容易被忽视,但可能引发严重后果。程序员在使用系统调用时,应始终保持警惕,对用户输入进行严格验证和过滤,避免因不当使用系统调用而导致安全风险。例如,在处理用户输入作为命令执行时,要确保输入的合法性和安全性,防止恶意代码注入。 - 多种系统调用的选择与权衡:文件详细介绍了
system()
、exec()
和fork()
等多种系统调用,它们各有优缺点和适用场景。在实际编程中,需要根据具体需求进行选择和权衡。例如,system()
函数简单易用但控制有限且存在安全隐患,适用于简单的命令执行场景;exec()
函数提供了更精确的控制,但使用相对复杂;fork()
函数则用于创建进程副本,结合exec()
函数可实现多进程并发执行,适用于需要提高程序性能和并行处理任务的情况。程序员应深入理解这些系统调用的特性,根据实际情况合理运用,以达到最佳的程序效果。 - 跨平台编程的考虑:文中提及了不同操作系统下系统调用的差异,如
system()
函数在不同系统中执行不同命令,fork()
函数在Windows系统中不被原生支持(需通过Cygwin等工具实现)。在跨平台编程时,这是一个重要的考虑因素。程序员需要了解目标平台的特性,选择合适的系统调用或采取兼容性措施,确保程序在不同操作系统上能够正确运行。例如,在编写跨平台程序时,可能需要针对不同操作系统使用条件编译指令来选择合适的代码路径,以实现系统调用的正确使用。 - 错误处理的全面性:对于系统调用的错误处理机制,文件进行了详细介绍,包括
errno
变量和strerror()
函数的使用。在实际编程中,完善的错误处理是保证程序健壮性的关键。程序员不仅要能够检测到系统调用的失败,还应准确获取错误信息,以便及时采取相应措施,如向用户输出错误提示、记录日志或进行错误恢复操作。忽视错误处理可能导致程序在遇到问题时崩溃或出现不可预期的行为,因此应养成良好的错误处理习惯,全面考虑各种可能的错误情况并进行妥善处理。
学习思维导图(2分)
要求
- Mermaid 代码与截图(参考Mermaid MindMap语法)或者提交思维导图链接(如果使用线上编辑器,推荐processon,xmind,…)
思维导图
代码
mindmaproot((第九周预习报告系统调用与进程管理 ))系统调用system函数执行命令字符串安全性和灵活性问题系统调用依赖操作系统进程控制exec函数族execl、execlp、execleexecv、execvp、execve进程替换当前进程替换为新程序错误处理errno变量全局错误值strerror函数错误代码转换为消息环境变量环境变量的使用getenv读取环境变量execle传递环境变量fork函数与exec函数组合使用fork创建子进程父进程与子进程exec在子进程中运行新程序子进程替换为新程序父进程继续执行::icon(fa fa-book)
导图
基于 AI 的学习(2分)
要求
- 至少找到自己理解不是太好 2 个概念,让 AI 对自己进行苏格拉底提问
- 参考下面提示语或者使用 AI Agent
提示词:“我在学习XXX知识点,请你以苏格拉底的方式对我进行提问,一次一个问题”
- 核心是要求AI工具:“请你以苏格拉底的方式对我进行提问”
- 然后AI工具就会给你提问,如果不知道问题的答案,可以反问AI:“你的理解(回答)是什么?”
- 如果你觉得差不多了,可以先问问AI工具:“针对我XXX知识点,我理解了吗?”
- AI工具会给出它的判断,如果你也觉得自己想清楚了,可以最后问AI工具:“我的回答结束了,请对我的回答进行评价总结”,让它帮你总结一下。
学习内容
- system()函数
- 错误处理
学习实践过程遇到的问题与解决方式(AI 驱动,优先使用AI工具解决问题)(2分)
- 问题 1未检查系统调用的返回值导致的错误
情景描述:
在编写程序时,可能会直接调用系统函数(如read(), write(), malloc()等)而忽略了对这些函数返回值的检查。如果这些函数调用失败,它们通常会返回特定的错误码,如果没有检查这些返回值,程序可能会继续执行错误的逻辑,导致不可预测的行为或程序崩溃。
解决方式:
检查返回值:每次调用系统函数后,应立即检查其返回值。如果返回值表明错误,应执行错误处理代码。
使用宏定义:在代码中定义宏,如CHECK_ERR,用于检查函数调用的返回值,并在发现错误时执行错误处理逻辑。
日志记录:记录关键系统调用的错误信息,以便于调试和追踪问题来源。
- 问题 2对错误信息的处理不当导致用户体验差
情景描述:
在错误发生时,如果程序只是简单地打印出错误码或技术性的错误信息,对于普通用户来说可能难以理解。这不仅影响了用户体验,还可能导致用户在遇到问题时不知道如何操作。
解决方式:
用户友好的错误信息:为错误情况提供清晰、简洁、用户友好的错误信息。避免直接显示技术性的错误码或复杂的错误信息。
错误日志记录:在后台记录详细的错误信息,包括错误码和堆栈跟踪,以便于开发人员分析和调试。
错误恢复建议:在可能的情况下,提供错误恢复的建议或操作步骤,帮助用户解决问题。
作业提交要求(1分)
- 提交Markdown 文件,文档命名“学号姓名《密码系统设计》.md”
- 提交Markdown 文件转为 PDF,文档命名“学号姓名《密码系统设计》第 X 周.pdf”
- 提交代码托管链接(可选):学号姓名 gitee(github) 链接
- 内容质量高有加分
参考资料
- AI工具(你使用的AI工具及其链接)
- Kimi
- 秘塔搜索
- …
- 图书
- 《Windows C/C++加密解密实战》
- …
- 网站
- gmssl官网
- openssl
- …