Linux(5)底层分析-常见问题-经典笔试面试题整理

news2024/11/30 18:45:54

六、底层分析

1、linux 目录

Linux各路径的解释:

/bin存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里
/home存放所有用户文件的根目录,是用户主目录的基点,比如用户user的主目录是/home/user,可以用~user表示
/home/admin用的是admin的空间
/usr用于存放系统应用程序,可以理解为C:/Windows/
/usr/local用户级的程序目录,可以理解为C:/Progrem Files/;用户自己编译的软件默认会安装到这个目录下;本地系统管理员软件安装目录(安装系统级的应用);这是最庞大的目录,要用到的应用程序和文件几乎都在这个目录;用的是root的空间。
/usr/lib理解为 C:/Windows/System32
/root超级用户(系统管理员)的主目录
/dev用于存放设备文件
/tmp用于存放各种临时文件,是公用的临时文件存储点
/etc存放系统管理和配置文件
/opt放置第三方大型软件(或游戏),可以理解为D:/Software
/usr/src系统级的源码目录
/usr/local/src用户级的源码目录

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2、初步介绍

Linux 操作系统是一个基于 Unix 的开源操作系统。它的底层主要由内核组成,负责管理系统的资源,如处理器、内存、输入/输出设备等。在 Linux 内核之上,有一系列的用户空间程序和系统调用接口,这些程序和接口为用户提供了与内核交互的途径。

1. Linux 内核

Linux 内核是操作系统的核心部分,负责管理系统的资源,并提供基本的服务。内核的主要功能包括:

  • 进程管理:负责进程的创建、销毁、调度和同步。
  • 内存管理:负责内存的分配和回收,以及内存的保护和共享。
  • 文件系统:负责文件的存储、读取、写入和删除。
  • 设备驱动:负责与硬件设备进行交互,如硬盘、键盘、鼠标等。
  • 网络通信:负责数据的传输和接收,包括 TCP/IP 协议栈的实现。
2. 系统调用

系统调用是用户空间程序与内核交互的一种方式。通过系统调用,用户空间程序可以请求内核执行某些特定的操作,如创建文件、执行进程等。
例如,open 系统调用用于打开文件。当用户空间程序调用 open 函数时,它会触发相应的系统调用,内核会执行打开文件的操作,并返回一个文件描述符。用户空间程序可以通过这个文件描述符来进行后续的读写操作。

3. 用户空间程序

用户空间程序是在用户空间运行的程序,它们不直接与硬件交互,而是通过系统调用请求内核执行特定的操作。
例如,ls 命令用于列出目录中的文件和文件夹。当您在终端中输入 ls 并按下回车键时,ls 程序会在用户空间运行。它会请求内核列出当前目录下的文件和文件夹,然后将结果返回给用户空间程序,最后输出到终端。

4. 设备驱动

设备驱动是内核的一部分,负责与硬件设备进行交互。设备驱动为用户提供了一个抽象的接口,使得用户不需要关心硬件的具体实现细节。
例如,显卡驱动负责与显卡进行交互,将用户空间程序生成的图像数据渲染到屏幕上。当您运行一个图形界面程序时,内核的显卡驱动会处理图像数据的渲染工作。

总结

Linux 操作系统的底层主要由内核、系统调用、用户空间程序和设备驱动组成。这些组件相互协作,为用户提供了一个稳定、高效和可扩展的操作系统环境。通过理解这些底层组件的工作原理,您可以更好地掌握 Linux 系统的运行机制,从而更好地管理和优化系统资源。

3、深入介绍

深入了解 Linux 操作系统的底层涉及到对硬件的直接操作,操作系统内核的源代码分析,以及系统调用和设备驱动程序的具体实现。以下是一些更详细的解释和深入的探讨。

1. 内核源代码

Linux 内核的源代码是开源的,您可以在 GitHub 上找到它的存储库:https://github.com/torvalds/linux。内核源代码包含了多个子系统,如进程管理、内存管理、文件系统、网络栈、设备驱动等。

示例:查看内核源代码

cd /path/to/linux/kernel/source
git status

这个命令会显示当前 Linux 内核源代码的版本和变更情况。

2. 系统调用表

系统调用是通过中断向量表映射到的内核函数。在 Linux 中,每个系统调用都有一个唯一的数字标识(系统调用号)。

示例:查看系统调用号

cat /usr/include/asm/unistd.h

这个命令会显示 Linux 系统调用号列表。

3. 设备驱动程序

设备驱动程序通常位于内核空间,它们直接与硬件接口。驱动程序的源代码通常位于内核源代码的 drivers 目录中。

示例:查看显卡驱动源代码

cd /path/to/linux/kernel/source/drivers/video

这个命令会切换到显卡驱动程序的源代码目录。

4. 系统调用的高级实现

系统调用的高级实现涉及到用户空间程序如何通过特定的 API 调用来发起系统调用,以及内核如何处理这些调用。

示例:open 系统调用的 C 库实现

#include <fcntl.h>
int open(const char *path, int flags) {
    return syscall(SYS_open, path, flags);
}

这个 open 函数实现了一个系统调用。SYS_open 是系统调用号,它告诉内核执行 open 系统调用。

5. 设备驱动的高级实现

设备驱动的高级实现涉及到内核如何与硬件设备进行交互,以及如何处理设备的中断和 I/O 请求。

示例:显卡驱动的中断处理

static irqreturn_t video_irq(int irq, void *dev_id) {
    // 处理显卡中断
    return IRQ_HANDLED;
}

这个函数处理显卡设备的中断。

6. 内核模块

内核模块是内核的一部分,它们可以被动态加载和卸载。模块的源代码通常位于内核源代码的 kernel/ 目录中。

示例:查看内核模块源代码

cd /path/to/linux/kernel/source/kernel

这个命令会切换到内核模块的源代码目录。

7. 总结

Linux 操作系统的底层分析需要深入理解内核源代码、系统调用、设备驱动程序和内核模块。这些组件的实现细节可以在 Linux 内核的源代码中找到。通过阅读和研究这些源代码,您可以获得对 Linux 操作系统底层工作原理的深入了解。

4、源码部分解读

Linux 源码是一个庞大且复杂的软件项目,它包含了数百万行代码。Linux 内核源码主要包含了操作系统内核的相关实现,而 Linux 操作系统还包括了用户空间的应用程序、库、系统管理工具等。

1、解读 Linux 源码的指导
  1. 了解基础知识:在解读 Linux 源码之前,您需要具备一定的计算机操作系统原理、C 语言编程、数据结构与算法等基础知识。
  2. 阅读官方文档:Linux 内核的官方文档是理解源码的重要资源。这些文档通常包含了内核的设计理念、架构、各个模块的功能介绍等。
  3. 选择合适的切入点:由于源码非常庞大,您可以选择从感兴趣的模块或功能开始。比如,如果您对文件系统感兴趣,可以从 fs 目录开始;如果您对网络感兴趣,可以从 net 目录开始。
  4. 阅读源码:从高层次的代码开始阅读,逐渐深入到具体的实现细节。在阅读过程中,您可能需要不断地查阅数据结构、算法相关的资料,以及内核的其他部分的代码。
  5. 实际运行和测试:尝试编译和运行 Linux 内核,以便更好地理解代码的实际运行方式和效果。您还可以尝试修改代码并观察修改后的影响。
  6. 加入社区:Linux 开源社区是非常活跃的。您可以通过加入邮件列表、论坛等方式,与其他开发者交流和讨论。
  7. 持续学习和实践:解读 Linux 源码是一个持续的学习过程。随着技术的发展和 Linux 内核的更新,您需要不断地学习和实践。
2、解读 Linux 内核的调度器代码过程步骤
  1. 理解调度器的基本功能
    • 调度器是内核中的一个组件,负责决定哪个进程将获得处理器时间。
    • 它管理着进程的状态转换,包括就绪、运行、阻塞等。
    • 学习调度器的关键数据结构,如进程池、调度队列、优先级等。
  2. 阅读相关文档和源码
    • 查看 Linux 内核文档中关于调度器的部分。
    • 阅读调度器的源码,通常位于内核源码的 kernel/sched 目录。
  3. 学习调度器的算法
    • 调度器使用多种算法来决定进程的执行顺序,如轮转调度(Round Robin)、优先级调度等。
    • 研究这些算法在 Linux 内核中的具体实现。
  4. 实际分析和调试
    • 使用内核调试工具(如 kdumpkgdb 等)来分析调度器的运行。
    • 在本地机器上编译和运行 Linux 内核,以实际观察调度器的行为。
  5. 参与社区讨论
    • 加入 Linux 内核邮件列表,参与关于调度器的讨论。
    • 阅读和学习社区中的相关patch和讨论 thread。

举例详解:pick_next_task 函数

假设我们找到了 pick_next_task 函数的定义,它可能看起来像这样(这里只是一个简化的示例):

struct task_struct *pick_next_task(struct rq *rq) {  
    struct task_struct *next = NULL;  
    struct prio_array *array = &rq->active;  
    unsigned long idx = 0;  
  
    if (!array->nr_active)  
        goto idle;  
  
    for (idx = 0; idx < MAX_PRIO; ++idx) {  
        struct list_head *queue = array->queue + idx;  
        if (!list_empty(queue)) {  
            next = list_entry(queue->next, struct task_struct, run_list);  
            break;  
        }  
    }  
  
    if (!next)  
        goto idle;  
  
    // ... 其他逻辑,如负载均衡、调度策略等 ...  
  
    return next;  
  
idle:  
    return rq->idle;  
}

在这个简化的示例中,pick_next_task 函数遍历了不同优先级的就绪队列,以找到下一个要运行的进程。它首先检查是否有任何活动进程(nr_active),然后遍历每个优先级队列,直到找到一个非空的队列。然后,它从该队列中选择第一个进程作为下一个要运行的进程。如果没有找到任何进程,则选择空闲进程(rq->idle)作为默认选项。

3、关于解读 Linux 源码的在线课程和书籍:
  • Linux Kernel Development(Linux 内核开发)
  • Linux Kernel internals(Linux 内核内部)
  • Introduction to Linux(Linux 简介) - 重点是命令行操作,但也涉及一些内核概念
    书籍:
  • “Linux Kernel Development” by Robert Love
  • “Understanding Linux Internals” by 作者:Rick Forensics
  • “Linux Device Drivers” by 作者:Robert Love
  • “The Linux Programming Interface” by 作者:Michael Kerrisk
4、 Linux 文件系统的具体实现
  1. 理解文件系统的基础知识
    • 学习文件系统的概念,如目录结构、文件权限、文件系统类型等。
  2. 阅读文件系统的源码
    • Linux 内核中的文件系统源码通常位于 fs 目录。
    • 研究不同文件系统(如 ext4、XFS、Btrfs)的实现细节。
  3. 理解核心数据结构
    • 学习文件系统中的关键数据结构,如超级块、inode、 dentry、文件描述符等。
  4. 跟踪文件操作
    • 跟踪文件系统中的常见操作,如打开、读取、写入、关闭等。
  5. 使用调试工具
    • 使用内核调试工具(如 fs_debug)来分析文件系统的行为。
  6. 实际测试和实验
    • 在虚拟机或隔离的环境中测试文件系统的功能。
    • 尝试编写简单的文件系统或修改现有文件系统。
      通过上述步骤,您可以逐步深入理解 Linux 文件系统的实现细节。记住,阅读和理解内核源码是一个逐步的过程,需要耐心和持续的学习。

七、常见问题

1、Linux系统(vm中)能ping通宿主机,宿主机ping不通Linux系统?

问题原因:

  • 网络配置问题:虚拟机的网络配置可能不正确,例如,虚拟机的网关设置错误或者虚拟机没有配置正确的默认网关。
  • 防火墙设置:宿主机的防火墙可能阻止了来自虚拟机的流量。
  • 虚拟网络适配器:虚拟机的网络适配器可能没有正确连接到宿主机的网络。

解决措施:

  • 检查虚拟机的网络配置,确保网关设置正确。
  • 查看宿主机的防火墙设置,确保允许虚拟机发出的流量。
  • 检查虚拟机的网络适配器状态,确保它已连接并且配置正确。

示例1:网络连接打开。

在这里插入图片描述

2. Linux 系统无法连接到无线网络

问题原因:

  • 无线网卡驱动问题:Linux 系统可能没有正确安装无线网卡的驱动。
  • 无线网络配置问题:无线网络的 SSID、密码或其他配置参数可能不正确。
  • 无线网络信号问题:无线网络信号弱,导致无法连接。

解决措施:

  • 检查无线网卡驱动是否已安装并且是最新的。
  • 检查无线网络的 SSID 和密码是否正确。
  • 移动设备到信号更强的位置。

3. SSH 连接超时或失败

问题原因:

  • 网络问题:宿主机与虚拟机之间的网络连接可能不稳定或速度慢。
  • SSH 服务配置问题:虚拟机上的 SSH 服务可能没有正确配置或未启动。
  • 防火墙或安全组设置:可能阻止了 SSH 流量。

解决措施:

  • 检查网络连接是否稳定,并尝试使用 ping 测试。
  • 确保虚拟机上的 SSH 服务已启动,并且配置正确。
  • 查看防火墙或安全组设置,确保允许 SSH 流量。

4. 文件传输速度慢

问题原因:

  • 网络带宽限制:网络带宽可能不足,导致文件传输速度慢。
  • 网络拥堵:网络可能因为拥堵而导致速度下降。
  • 文件大小:大型文件传输 naturally 会更慢。

解决措施:

  • 检查网络带宽和网络流量,确定是否有人在同时使用网络。
  • 尝试在网络负载较低的时段进行文件传输。
  • 使用压缩工具压缩文件再传输,以减少传输时间。

5. 时间同步问题

问题原因:

  • 网络时间协议(NTP)服务未配置或不可用。
  • 防火墙阻止了 NTP 流量。
  • 系统时区设置不正确。

解决措施:

  • 确保虚拟机和宿主机都配置了 NTP 服务,并且能够访问外部 NTP 服务器。
  • 查看防火墙设置,确保允许 NTP 流量。
  • 检查系统时区设置,确保时区正确设置为本地时区或 UTC。

总结

​ 这些问题的解决通常需要系统的排查步骤,包括检查网络配置、防火墙设置、服务状态和系统日志。在处理这些问题时,耐心和细致是非常重要的。此外,确保虚拟机的操作系统和驱动程序都是最新的,也往往能够解决许多问题。

八、Linux经典笔试面试题

1、请简述Linux操作系统的主要特点。

Linux是一个开源的类Unix操作系统,具有开放源代码、可定制性强、稳定性高、多用户、多任务和跨平台等特点。

2、请简述进程和线程的区别。

进程是计算机中程序执行的基本单位,每个进程都有独立的内存空间和系统资源。线程是进程内部的一个执行流程,线程共享进程的内存空间和系统资源。进程和线程的主要区别在于资源占用和调度级别。

3、请写出三个常用的Linux命令,并简要说明它们的作用。
  • ls:列出目录中的文件和子目录。
  • cd:切换当前目录。
  • cp:复制文件或目录。
4、请解释Linux文件权限的表示方法。

Linux文件权限采用三位八进制数表示,分别代表文件所有者、组用户和其他用户的读、写、执行权限。例如,755 表示文件所有者具有读、写、执行权限,组用户和其他用户具有读和执行权限。

5、请写出一条Linux查找文件的命令。
  • find /path/to/search -name "filename":在指定路径下查找名为 “filename” 的文件。
6、请解释Linux中的VFS(虚拟文件系统)的作用。

VFS是Linux内核中的一种抽象层,它将不同的文件系统(如ext4、ntfs等)统一成一个虚拟的文件系统,使得用户和应用程序可以透明地访问不同类型的文件系统。

7、请简述TCP和UDP协议的区别。

TCP(传输控制协议)是一种面向连接、可靠的数据传输协议,具有错误检测和纠正功能。UDP(用户数据报协议)是一种无连接、不可靠的数据传输协议,速度快但传输过程中可能丢失数据。

8、请写出一条Linux命令,用于查看当前系统的负载情况。
  • top:查看当前系统的负载情况,包括进程、内存、CPU等使用情况。
9、请解释Linux中的硬链接和软链接的区别。

硬链接是文件系统中的一个目录条目,它指向文件数据块的实际位置。软链接(符号链接)是一个特殊的文件,它包含的是另一个文件的路径名。硬链接和软链接的主要区别在于,硬链接指向的是文件的数据块,而软链接指向的是文件的路径名。

10、请写出一条Linux命令,用于查看当前系统的CPU使用情况。
  • htop:查看当前系统的CPU使用情况,包括进程、内存、负载等统计信息。

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

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

相关文章

iOS - Runtime - Class-方法缓存(cache_t)

文章目录 iOS - Runtime - Class-方法缓存(cache_t)1. 散列表的存取值 iOS - Runtime - Class-方法缓存(cache_t) Class内部结构中有个方法缓存&#xff08;cache_t&#xff09;&#xff0c;用散列表&#xff08;哈希表&#xff09;来缓存曾经调用过的方法&#xff0c;可以提高…

A fatal error occurred: MD5 of file does not match data in flash!问题解决

采用的芯片是ESP32-S3-WROOM&#xff0c;16MB FLASH 开发环境是Arduino&#xff0c;烧录到100%后直接报错。 以为是Arduino的问题&#xff0c;用esp-idf开发的程序&#xff0c; 烧录的过程中&#xff0c;也是直接报错如下&#xff1a; esptool.py v4.7.0 Serial port /dev/…

什么是缓冲区溢出攻击?

缓冲区是内存存储区域&#xff0c;在数据从一个位置传输到另一个位置时临时保存数据。当数据量超过内存缓冲区的存储容量时&#xff0c;就会发生缓冲区溢出&#xff08;或buffer overrun&#xff09;。结果&#xff0c;试图将数据写入缓冲区的程序会覆盖相邻的内存位置。 例如…

java组合总和2(力扣Leetcode40)

组合总和 II 力扣原题链接 问题描述 给定一个候选人编号的集合 candidates 和一个目标数 target&#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 每个数字在每个组合中只能使用一次。 注意&#xff1a;解集不能包含重复的组合。 示例 示例 1: 输入:…

【倪琴神品品鉴】全新倪诗韵神品级古琴

倪琴朱砂神品仲尼&#xff0c;仅此放漏一张&#xff1b;龙池侧签海门倪诗韵制&#xff0c;雁足上方刻“雷音琴坊”方章&#xff0c;凤沼下方有随形章“神品”二字&#xff1b;老木材纹理竖直&#xff0c;共振良好&#xff0c;是难得的佳器&#xff1b;附带倪老师亲笔签名收藏证…

【机器学习之---数学】随机游走

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 随机游走 1. 概念 1.1 例1 在你的饮食俱乐部度过了一个富有成效的晚上后&#xff0c;你在不太清醒的状态下离开了。因此&#xff0c;你会醉醺醺地在展…

JUC:wait/notify用法并写一个简单消息队列(生产者消费者问题)

文章目录 wait/notifyapiwait vs sleep手写消息队列 wait/notify 这块比较简单&#xff0c;就不在把所有例子都写上了。 要注意区分waitSet和EntryList中的线程&#xff0c;一个获得了锁但是wait释放了锁进入等待notify唤醒状态&#xff0c;一个是正在等待获得锁。 不过相同点…

算法之并查集

并查集&#xff08;Union-find Data Structure&#xff09;是一种树型的数据结构。它的特点是由子结点找到父亲结点&#xff0c;用于处理一些不交集&#xff08;Disjoint Sets&#xff09;的合并及查询问题。 Find&#xff1a;确定元素属于哪一个子集。它可以被用来确定两个元…

wps斜线表头并分别打字教程

wps斜线表头怎么做并分别打字&#xff1a; 1、首先选中我们想要设置的表头。 2、接着右键选中它&#xff0c;点击“设置单元格格式” 3、然后点击上方“边框”选项卡。 4、随后选择图示的斜线&#xff0c;点击“确定” 5、设置完成后&#xff0c;我们只要在其中打字就可以在斜…

vue-v-for遍历index与id

一.遍历列表key的作用&#xff08;index作为key&#xff09; 虚拟DOM上有key,是虚拟的&#xff0c;但是真实DOM上没有&#xff0c;key是Vue内部的 当使用index作为key的时候&#xff0c;Vue会根据初识数据生成一个初始的虚DOM&#xff0c; 然后在页面上映射出真实DOM 如果向数据…

vue 窗口内容滚动到底部

onMounted(() > {scrollToBottom() }) // 滚动到底部方法 const scrollToBottom () > {// 获取聊天窗口容器let chatRoom: any document.querySelector(".chat-content");// 滚动到容器底部chatRoom.scrollTop chatRoom.scrollHeight; } 效果 聊天窗口代码…

HashMap关键源码带读

文章目录 目录 文章目录 前言 1 . 成员变量 灵魂五问 第一问: 默认初始化容量为啥是16? 第二问: 最大容量为什么必须是2的幂? 第三问: 链表转红黑树的阈值为什么是8? 第四问: 红黑树转链表的阈值为什么是6? 第五问: 默认加载因子为什么是0.75? 2. 成员方法 eq…

Discuz采集发布插件

Discuz&#xff08;简称DZ&#xff09;是一款知名的开源论坛系统&#xff0c;广泛应用于各类网站社区。对于许多站长来说&#xff0c;保持论坛内容的更新是一项挑战&#xff0c;特别是在内容量庞大的情况下。为了解决这个问题&#xff0c;有一类特殊的插件是用于在Discuz论坛中…

《QT实用小工具·四》屏幕拾色器

1、概述 源码放在文章末尾 该项目实现了屏幕拾色器的功能&#xff0c;可以根据鼠标指定的位置识别当前位置的颜色 项目功能包含&#xff1a; 鼠标按下实时采集鼠标处的颜色。 实时显示颜色值。 支持16进制格式和rgb格式。 实时显示预览颜色。 根据背景色自动计算合适的前景色…

国内好用的chatGPT和AI绘图工具

分享一个比较好用的AI 分享一个比较好用的AI&#xff0c;只是需要开通会员&#xff0c;目前官网的价格是&#xff1a;298&#xff0c;开通之后可以使用chatgpt4、AI绘画、图片融合等等&#xff01;不开通的话是可以免费使用15次的&#xff0c;下面是一些介绍图片&#xff01;链…

安全团队需要重点演练的四大威胁

文章目录 前言一、勒索软件攻击二、第三方风险三、内部威胁四、分布式拒绝服务攻击(DDoS)前言 桌面演练(推演)是一种重要的安全演习形式,参演人员利用演练方案、流程图、计算机模拟、视频会议等辅助手段,针对事先假定的演练情景,讨论和推演应急决策及现场处置,从而促使相…

点点数据K参数加密逆向分析(RPC方案跟加密算法还原)

文章目录 1. 写在前面2. 接口分析3. 断点分析4. RPC调用5. 算法还原 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长…

蓝桥杯物联网竞赛_STM32L071_13_定时器

CubeMx配置LPTIM: counts internal clock events 计数内部时钟事件 prescaler 预分频器 updata end of period 更新期末 kil5配置&#xff1a; 中断回调函数完善一下&#xff1a; void HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim){if(cnt ! 10) cnt…

用Python实现办公自动化(自动化处理Excel工作簿)

自动化处理Excel工作簿 &#xff08;一&#xff09;批量生产产品出货清单 以“出货统计表”为例&#xff0c; 需求&#xff1a;将出货记录按照出货日期分类整理成多张出货清单 “出货统计表数据案例” “产品出货清单模板” 1.提取出货统计表的数据 “Python程序代码” # 使用…

计算机毕业设计Python+Spark知识图谱高考志愿推荐系统 高考数据分析 高考可视化 高考大数据 大数据毕业设计 机器学习 深度学习 人工智能

学院&#xff08;全称&#xff09;&#xff1a; 专业&#xff08;全称&#xff09;&#xff1a; 姓名 学号 年级 班级 设计&#xff08;论文&#xff09; 题目 基于Spark的高考志愿推荐系统设计与实现 指导教师姓名 职称 拟…