【Linux】内核结构

news2024/12/23 21:03:41

一、Linux内核结构介绍

  • Linux内核结构框图

二、图解Linux系统架构
三、驱动认知

  • 1、为什么要学习写驱动
  • 2、文件名与设备号
  • 3、open函数打通上层到底层硬件的详细过程

四、Shell

  • Shell脚本

一、Linux内核结构介绍

Linux 内核是操作系统的核心部分,它负责管理系统的资源、进程调度、设备驱动程序等核心功能。以下是 Linux 内核的主要组成部分和结构:

  1. 进程管理:

    • 调度器(Scheduler): 决定在多任务系统中哪个进程获得 CPU 时间。
    • 进程控制块(Process Control Block,PCB): 存储有关进程的信息,如寄存器状态、进程状态等。
  2. 内存管理:

    • 虚拟内存管理: 管理进程的虚拟地址空间,包括分页机制、页面置换等。
    • 物理内存管理: 负责跟踪系统中的物理内存,包括内存分配、释放等。
  3. 文件系统:

    • 虚拟文件系统(VFS): 提供文件系统的抽象接口,使得不同类型的文件系统可以共享相同的 API。
    • 文件描述符表: 管理打开文件的信息,每个进程都有一个文件描述符表。
  4. 设备驱动程序:

    • 字符设备和块设备驱动: 用于管理字符设备(如终端)和块设备(如硬盘)。
    • 网络设备驱动: 处理网络设备和协议栈。
  5. 网络协议栈:

    • TCP/IP 协议栈: 包括网络层、传输层等,用于实现网络通信。
    • 套接字层: 提供应用程序与网络协议栈之间的接口。
  6. 系统调用接口:

    • 系统调用: 提供用户空间程序与内核之间的接口,允许用户程序请求内核执行特权操作。
  7. 中断和异常处理:

    • 中断处理程序: 处理硬件中断,允许外部设备向 CPU 发送信号。
    • 异常处理程序: 处理由于错误或异常情况而引发的事件。
  8. 定时器和时钟管理:

    • 内核定时器: 用于实现计时和时间管理。
    • 实时时钟(RTC): 处理硬件时钟。
  9. 同步和互斥机制:

    • 信号量、自旋锁、互斥体等: 用于确保多个进程或线程之间的同步和互斥。
  10. 系统初始化和启动:

  • 引导加载程序(Bootloader): 负责加载内核镜像到内存中。
  • 启动过程: 初始化硬件、文件系统等,最终执行第一个用户空间进程。

这些组件一起构成了 Linux 内核的核心结构。内核的源代码是 modulized 的,允许添加或删除特定功能的模块,以适应不同的需求。整个内核的结构和实现细节非常庞大,具体的功能和特性取决于具体的内核版本和配置。

Linux内核结构框图

对内核结构框图有个总体的把握,有助于理解为什么驱动要这样写,为什么写的应用程序所用的C库接口能够产生这么多的事情。
在这里插入图片描述
函数库就像一个“黑匣子”,提供了一系列API支配内核运作,但你不知道内核发生了什么。

内核是一个很厉害的超级逻辑,把硬件底层的东西抽象化,对用户来说只需要调API就好了,根本不需要管寄存器,协议,总线…(单片机会去直接操作),这些全部由操作系统做好。动不动写个操作系统是不现实的。

能把字符设备,块设备的设备驱动吃透,已经是一个很厉害的工程师了。

二、图解Linux系统架构

在这里插入图片描述
  最内层是硬件,最外层是用户应用,比如浏览器等等。硬件是物质基础,而应用提供服务。

  为了方便调用内核,Linux将内核的功能接口制作成系统调用(system call)。用户不需要了解内核的复杂结构,就可以使用内核。系统调用是操作系统的最小功能单位。一个操作系统,以及基于操作系统的应用,都不可能实现超越系统调用的功能

  系统调用提供的功能非常基础,所以使用起来很麻烦。一个简单的给变量分配内存空间的操作,就需要动用多个系统调用。Linux定义一些库函数(library routine)来将系统调用组合成某些常用的功能。上面的分配内存的操作,可以定义成一个库函数,比如常用的malloc

三、驱动认知

驱动(Driver)是一种用于使操作系统与硬件或其他软件交互的程序或模块。驱动程序充当操作系统与硬件之间的桥梁,允许它们有效地通信和协作。以下是关于驱动的一些基本认知:

  1. 硬件与操作系统的交互: 操作系统本身并不了解所有硬件设备的细节。驱动程序提供了一个标准的接口,使得操作系统能够与硬件设备进行通信,而无需了解设备的底层细节。

  2. 功能和作用:

    • 设备驱动: 控制和管理硬件设备,如打印机、图形卡、网络适配器等。
    • 文件系统驱动: 提供对不同文件系统的支持,例如 FAT、NTFS、ext4 等。
    • 虚拟设备驱动: 创建虚拟设备,如虚拟磁盘、虚拟网络设备等。
    • 字符设备驱动和块设备驱动: 用于字符设备(如终端)和块设备(如硬盘)的控制。
    • 网络设备驱动: 管理网络接口卡和网络协议栈的通信。
  3. 驱动模型:

    • Monolithic Kernel 模型: 驱动程序直接链接到内核,与内核一起运行。
    • Microkernel 模型: 驱动程序运行在用户空间,与内核通过 IPC 进行通信。
  4. 编写和调试:

    • 语言: 驱动程序通常使用 C 语言编写。
    • 调试: 驱动的调试比应用程序更具挑战性,通常需要使用特定的调试工具。
  5. 加载和卸载:

    • 加载: 操作系统在启动时或需要设备支持时加载相应的驱动。
    • 卸载: 驱动可在不需要时从内存中卸载。
  6. 稳定性和性能:

    • 稳定性: 驱动程序的稳定性对系统整体稳定性至关重要。
    • 性能: 驱动程序的效率影响系统性能,因此编写高效的驱动程序很重要。
  7. 硬件抽象层(Hardware Abstraction Layer,HAL):

    • 驱动程序通常包括硬件抽象层,用于将硬件的具体实现细节隐藏起来,使得上层软件能够以标准化的方式与硬件交互。
  8. 硬件和操作系统的变化:

    • 驱动程序需要不断适应硬件和操作系统的变化。随着技术的进步和新硬件的推出,驱动程序需要进行更新和优化。

驱动程序是操作系统的关键组成部分之一,它们的正确性和性能直接影响到系统的稳定性和功能。在编写和维护驱动程序时,开发人员需要深入了解硬件和操作系统的工作原理。

1、为什么要学习写驱动

学习写驱动有许多重要的原因,尤其是对于嵌入式系统和底层硬件交互的开发者。以下是一些学习写驱动的关键原因:

  1. 硬件控制: 驱动是与硬件设备进行交互的桥梁。通过学习写驱动,你可以更好地理解和掌握如何控制硬件,包括传感器、执行器、通信设备等。

  2. 跨平台兼容性: 编写通用的驱动可以使你的代码跨平台兼容,不依赖于特定的硬件或平台。这对于未来在不同系统上进行开发是至关重要的。

  3. 定制化需求: 在一些特殊的应用场景中,可能需要对硬件进行定制化的开发。学会写驱动使你能够满足特定硬件需求,而不仅仅依赖于现有的库和工具。

  4. 系统优化和性能: 编写优化的驱动可以提高系统的性能。对于嵌入式系统或对性能要求较高的应用,了解并优化驱动是至关重要的。

  5. 学习系统内部原理: 编写驱动需要深入了解操作系统的内部原理,包括内存管理、中断处理、设备树等。这有助于提升对系统整体运行机制的理解。

  6. 适应不同的开发环境: 随着技术的发展,可能需要在不同的硬件平台上进行开发。通过学习写驱动,你能够适应不同的开发环境,不仅限于某个特定的开发板或平台。

  7. 理解底层通信协议: 编写驱动通常涉及与硬件之间的低层通信,这使你能够深入了解通信协议、寄存器配置等底层细节。

  8. 开发嵌入式系统: 对于嵌入式系统的开发者来说,掌握驱动编写是至关重要的,因为这些系统通常需要直接与硬件进行交互。

总的来说,学习写驱动提供了更深层次的系统开发技能,使开发者能够更全面、更灵活地应对各种硬件和开发场景。

原来树莓派开发使用厂家提供的wiringPi库,开发简单。
但未来做开发时,不一定都是用树莓派,没有wiringPi库可以用。但只要能运行Linux,linux的标准C库一定有。
学会根据标准C库编写驱动,只要能拿到linux内核源码,拿到芯片手册,电路图…就能做开发。

2、文件名与设备号

在 Linux 中,一切皆为文件的概念是核心思想之一。设备文件在 /dev 目录下,通过文件名和设备号来标识和区分硬件设备。以下是一些相关的概念和解释:

  1. 文件名: 文件名是用户空间应用程序访问设备的方式之一。通过打开 /dev 目录下的特定文件,应用程序可以与相应的设备进行交互。例如,/dev/sda 可以代表系统上的第一个硬盘设备。

  2. 设备号: 每个设备文件都与一个设备号相关联。设备号分为主设备号和次设备号两部分。

    • 主设备号: 用于区分不同种类的设备,它指定了设备驱动程序的入口点。
    • 次设备号: 用于区分同一类型下的多个设备,指定具体的设备实例。
  3. 设备号的管理: 设备号是通过 mknod 命令手动创建的,但通常由系统自动创建和管理。系统会为已注册的设备驱动程序分配设备号,这些信息存储在内核的设备链表中。

  4. 设备链表: 内核中存在一个设备链表,用于管理已注册的设备驱动程序。这个链表包含了每个设备驱动程序的信息,包括主设备号、设备名称、设备操作函数等。

  5. 加载驱动程序: 驱动程序通过 insmodmodprobe 命令加载到内核中。加载后,内核会将该驱动程序的信息加入设备链表中。

  6. 用户空间的操作: 当用户空间的应用程序调用 open 等系统调用时,内核会根据文件名找到相应的设备号,并查找设备链表以确定相应的设备驱动程序。这样,用户空间的应用程序就可以通过文件名访问硬件设备。

总体来说,文件名和设备号的组合提供了一种抽象的方式,使用户空间的应用程序能够以标准的文件 I/O 操作方式访问硬件设备,而无需了解底层硬件细节。这种抽象化的设计提高了系统的可移植性和灵活性。

在目录/dev下都能看到鼠标,键盘,屏幕,串口等设备文件,硬件要有相对应的驱动,那么open怎样区分这些硬件呢?
依靠文件名与设备号
在这里插入图片描述

crw-rw----+ 1 root video    81,   0 Dec 14 12:17 video0

这是一个设备文件的详细信息,解释如下:

  • crw-rw----+: 文件的类型和权限。这是一个字符设备文件,权限是读写,额外的加号表示文件有扩展属性。

  • 1: 这表示有一个硬链接指向该文件。

  • root: 文件的所有者是 root 用户。

  • video: 文件的所属组是 video 组。

  • 81, 0: 这是设备文件的主设备号和次设备号。在这个例子中,主设备号是 81,次设备号是 0。

  • Dec 14 12:17: 文件的最后修改时间是在 12 月 14 日的 12:17。

  • video0: 文件的名称是 video0。

这个设备文件属于 video 组,具有读写权限。主设备号为 81,次设备号为 0,表明它是一个视频设备。

主设备号和次设备号

设备号又分为:主设备号用于区别不同种类的设备;次设备号区别同种类型的多个设备。驱动插入到链表的位置(顺序)由设备号检索

内核中存在一个驱动链表,管理所有设备的驱动。 驱动开发无非以下两件事:

  • 编写完驱动程序,加载到内核
  • 用户空间open后,调用驱动程序(驱动程序就是操作寄存器来驱动IO口,单片机51,32就是这种操作)

3、open函数打通上层到底层硬件的详细过程

open 函数是用户空间应用程序通过系统调用访问文件的入口。打通上层到底层硬件的过程涉及几个步骤,主要包括:

  1. 用户空间调用: 应用程序在用户空间通过标准库函数 open 调用打开文件。该调用提供了文件路径和一些标志位参数。

    int fd = open("/dev/video0", O_RDWR);
    
  2. 系统调用: open 函数触发系统调用,导致应用程序从用户空间切换到内核空间。在内核空间,调用处理程序开始执行。

  3. 查找文件: 内核通过文件系统层次结构查找指定的文件。在这个例子中,是查找 /dev/video0 这个设备文件。

  4. 获取文件对象: 找到文件后,内核会创建一个文件对象(file structure)来代表该文件。这个文件对象包含了一系列与文件相关的信息,例如文件的位置、访问模式、设备号等。

  5. 权限检查: 内核会检查应用程序对文件的访问权限。如果应用程序没有足够的权限,open 将失败。

  6. 分配文件描述符: 成功后,内核为应用程序分配一个文件描述符,这个描述符是一个整数,用于标识文件对象。应用程序将使用这个描述符进行后续的文件操作。

  7. 调用文件操作函数: 对于设备文件,内核会调用相应的设备驱动程序中的文件操作函数。例如,open 操作可能触发设备驱动程序的 open 函数。

  8. 设备操作: 设备驱动程序中的 open 函数执行与设备相关的初始化或其他必要的操作。这可能包括分配设备资源、配置硬件等。

  9. 返回文件描述符: 如果所有步骤成功,open 系统调用返回文件描述符给应用程序,表示文件打开成功。

通过这个过程,open 函数从用户空间向内核发起请求,内核负责管理文件系统和与设备相关的硬件,最终建立起用户空间应用程序与底层硬件的连接。

用户空间调用open

用户空间调用open(比如open(“/dev/pin4”,O_RDWR))产生一个软中断(中断号是0x80),进入内核空间调用sys_call,这个sys_call在内核里面是汇编的,用Source Insight搜索不到。

sys_calll真正调用的是sys_open(属于VFS层虚拟文件系统,因为磁盘的分区和引脚分区不一样,为了实现上层统一化),根据你的设备名比如pin4去到内核的驱动链表,根据其主设备号与次设备号找到相关驱动函数。

调用驱动函数里面的open,这个open就是对寄存器的操作,从而设置IO口引脚电平。这件事对于单片机来说特变容易,就两句话搞定:

sbit pin4 = P1^4;
pin4 = 1;

在这里插入图片描述

四、Shell

Shell 是一种命令行解释器,允许用户与操作系统进行交互。它接受用户输入的命令,并将其解释为操作系统能理解的指令。以下是一些关于 Shell 的基本信息:

  1. 命令解释器: Shell 解释用户输入的命令并将其转化为系统调用或执行相应的程序。用户可以通过 Shell 发送命令,执行各种任务。

  2. 命令行界面: Shell 提供了一个命令行界面,用户通过键盘输入命令。这是与图形用户界面(GUI)相对的概念,GUI 提供了图形化的操作界面。

  3. 脚本语言支持: 大部分的 Shell 是脚本语言的解释器,允许用户编写脚本来执行一系列命令,实现复杂的任务。常见的 Shell 脚本语言包括 Bash、sh、zsh 等。

  4. 交互式和非交互式: 用户可以在交互式模式下逐行输入命令,也可以将一系列命令存储在脚本文件中,以非交互式模式执行。

  5. 环境变量: Shell 维护了一组环境变量,这些变量包含了有关当前用户和系统配置的信息。用户可以通过设置环境变量来影响 Shell 和其执行的命令的行为。

  6. 默认 Shell: Linux 系统中常见的 Shell 包括 Bash(Bourne Again SHell)、sh(Bourne Shell)、zsh(Z Shell)等。用户可以通过修改用户配置文件或使用 chsh 命令更改默认 Shell。

  7. 管道和重定向: Shell 提供了管道和重定向操作符,允许将命令的输出传递给其他命令,或将输入输出从/到文件。

  8. 通配符和通配符扩展: Shell 支持通配符,用于匹配文件名。通配符扩展是指 Shell 将通配符扩展为匹配的文件名列表。

  9. 命令历史: 大多数 Shell 记录用户输入的命令历史,用户可以通过按上下箭头键来浏览和重新执行之前的命令。

Shell 在操作系统中扮演着重要的角色,为用户提供了与操作系统交互的途径,使用户能够有效地管理系统、执行任务和编写自动化脚本。

例如:当我们输入ls -l 的时候,它将此字符串解释为

  • 1.在默认路径找到该文件(/bin/ls),
  • 2.执行该文件,并附带参数 -l
    在这里插入图片描述
    你可以通过这个窗口输入或者输出文本,这个文本直接传递给shell进行分析解释,然后执行,本质就是提供和内核交互的程序。

Shell脚本

在没有图形界面之前,shell充当了用户的界面,当用户要运行某些应用时,通过shell输入命令,来运行程序。shell是可编程的,它可以执行符合shell语法的文本,这样的文本叫做shell脚本(script)

Shell 脚本是一种由 Shell 解释器执行的文本文件,其中包含一系列的 Shell 命令。Shell 脚本提供了一种在命令行界面中编写和执行一系列命令的方式,允许用户自动化和批处理一些任务。

以下是一些关于 Shell 脚本的基本信息:

  1. 脚本文件格式: Shell 脚本通常以 .sh 为扩展名,但这不是必须的。脚本文件的第一行通常包含指定 Shell 解释器的路径,例如 #!/bin/bash 表示使用 Bash 解释器执行脚本。

  2. 权限设置: 在执行 Shell 脚本之前,需要为脚本文件添加执行权限。可以使用 chmod +x script.sh 命令为脚本添加执行权限。

  3. 语法: Shell 脚本遵循 Shell 的语法规则,包括变量、条件语句、循环、函数等。常见的 Shell 脚本语言包括 Bash、sh、zsh 等。

  4. 变量: 可以在 Shell 脚本中定义和使用变量,例如:

    # 定义变量
    name="John"
    
    # 使用变量
    echo "Hello, $name!"
    
  5. 流程控制: Shell 脚本支持条件语句和循环,允许根据条件执行不同的命令,或者重复执行一组命令。

    # 条件语句
    if [ "$name" == "John" ]; then
        echo "It's John!"
    else
        echo "It's not John!"
    fi
    
    # 循环
    for i in {1..5}; do
        echo "Count: $i"
    done
    
  6. 函数: 可以在 Shell 脚本中定义和调用函数,以实现代码的模块化。

    # 定义函数
    say_hello() {
        echo "Hello from the function!"
    }
    
    # 调用函数
    say_hello
    
  7. 命令替换: Shell 脚本支持使用反引号 ` 或 $() 将命令的输出嵌入到脚本中。

    # 命令替换
    current_date=`date`
    echo "Current date: $current_date"
    
  8. 输入输出重定向: 可以使用 <>>> 等运算符实现输入和输出的重定向。

    # 输出重定向
    echo "Hello, World!" > output.txt
    
    # 输入重定向
    cat < input.txt
    

通过编写 Shell 脚本,用户可以实现自动化任务、批处理作业,或者简化复杂的命令行操作。这使得 Shell 脚本成为系统管理员和开发人员的重要工具。

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

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

相关文章

【Android】MVC与MVP的区别,MVP网络请求实践

一、MVC模式 目录 一、MVC模式二、MVP模式 1、MVP的简单应用 1.1 导入相关依赖包并设置权限1.2 实现Model1.2 实现Presenter1.3 实现View1.4分析项目结构和绑定过程1.5效果展示 2、MVP结合RxJava 一、MVC模式 MVC&#xff08;Model(模型)——View(视图)——Controller(控制…

三层交换,DHCP的详解与VRRP

目录 一、三层交换 1、三层交换机的作用&#xff1a; 2.vlan的虚拟接口vlanif&#xff08;ifinterface接口&#xff09; 3.三层交换机实验 4.拓展实验​编辑 二、DHCP 1.自动获取ip地址&#xff1a; 2.DHCP的好处&#xff1a; 3.分配方式&#xff1a; 4.举例&#xff…

6.rk3588获取摄像头和激光雷达数据(用线程根据时间同步)

文件夹结构如下&#xff1a; 如果没有特殊说明&#xff0c;我们将py文件写在该路径里面。 保存数据的路径如下&#xff1a; ---img_lidar_save ---2023-12-13&#xff08;根据日期自动生成当天保存数据的文件夹) ---camera_data(相机数据文件夹&#xff09; ---image(保存相加…

C++1114新标准——模板模板参数(Template Template Parameter)、using

系列文章目录 C11&14新标准——Variadic templates&#xff08;数量不定的模板参数&#xff09; C11&14新标准——Uniform Initialization&#xff08;统一初始化&#xff09;、Initializer_list&#xff08;初始化列表&#xff09;、explicit C11&14新标准—— d…

SpringBoot 究竟是如何跑起来的

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《SpringBoot》。&#x1f3af;&#x1f3af; &…

怎么把文件转成附件放在公众号里?这篇教程给你详细说清楚

文件转附件&#xff0c;其实就是把文件上传到某个网站&#xff0c;获得文件的下载链接&#xff0c;从而放到文章或者其他地方供读者下载使用。因为公众号并不支持直接在文章里面添加下载链接&#xff08;至少订阅号不行&#xff09;&#xff0c;所以把文件转成下载链接的方式并…

怎么制作GIF动图?教你这几个简单方法

怎么制作gif动图&#xff1f;GIF动图是一种非常有趣且实用的图片格式&#xff0c;它能够以短小精悍的方式展示动画效果&#xff0c;因此在社交媒体和聊天应用中备受追捧。本文将向您介绍几种制作GIF动图的方法&#xff0c;让您轻松制作出自己的动图。 GIF动图制作方法一&#x…

Spark编程实验一:Spark和Hadoop的安装使用

一、目的与要求 1、掌握在Linux虚拟机中安装Hadoop和Spark的方法&#xff1b; 2、熟悉HDFS的基本使用方法&#xff1b; 3、掌握使用Spark访问本地文件和HDFS文件的方法。 二、实验内容 1、安装Hadoop和Spark 进入Linux系统&#xff0c;完成Hadoop伪分布式模式的安装。完成Ha…

【开源项目】智慧水厂—经典开源项目实景三维数字孪生智慧水厂

智慧水务可视化平台是以物联网IOT技术为核心&#xff0c;以数据库系统为支撑&#xff0c;以城市水资源安全提升和建造智能化为目标的智慧水务体系。飞渡科技利用数字孪生技术结合物联网IOT技术&#xff0c;建立起多个基础数据及管理层级矩阵&#xff0c;可以跨部门、跨层级进行…

【Java 集合】ConcurrentLinkedQueue

在日常中, 我们用到的数据结构有很多: 数组, 链表, 树等, 而在这些结构中, 还有一个叫做队列的存在。 和其他的集合相同, Java 原生提供了不同的实现。 而如果我们需要一个线程安全的队列的话, 可以基于实际的场景进行选择, 比如基于数组实现同时操作上会阻塞的 ArrayBlockingQ…

我们为什么经常使用List list = new ArrayList<>() 而不是ArrayListlist = new ArrayList<>()

为什么不直接去Arraylist list new Arraylist()&#xff1b;而是直接通过List list new ArrayList();使用接口的好处 在Java中&#xff0c;使用List接口声明ArrayList类的变量是一种良好的编程实践&#xff0c;因为这符合面向接口编程的原则。面向接口编程是一种编程范式&…

canvas基本绘制对象

目录 绘制画布 设置画布 绘制圆形 绘制矩形填充渐变色 绘制文字及文字样式 绘制画布 <canvas id"canvas" width"800" height"600"></canvas> 设置画布 //获得画布元素var canvasdocument.getElementById(canvas);var ctxca…

GitHub Universe 2023 Watch Party in Shanghai:开源开发者日盛会

目录 前言GitHub Universe 2023的背景开源开发者日活动亮点本次参会的意义活动日程最后 前言 作为全球最大的代码托管平台&#xff0c;GitHub每年都会举办一场令开源开发者们翘首以待的盛会——GitHub Universe&#xff0c;今年也不例外&#xff0c;就在2023年的12月10日&…

算法训练营Day14

#Java #二叉树层次遍历 #反转二叉树 开源学习资料 二叉树的层次遍历&#xff1a;力扣题目链接 二叉树的层次遍历很好理解&#xff1a; 就是从根结点一层一层地往下遍历&#xff08;同一层&#xff0c;从左到右&#xff09;&#xff1a; 迭代的方式很好理解&#xff1a;就是…

computed 和 watch 的奇妙世界:让数据驱动你的 Vue 应用(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

docker部署go gin框架 Windows环境

目录 文章目的是什么 环境介绍 Windows 环境下 docker 部署 go gin 详细步骤 运行容器时因为挂载文件可能会出现的问题 直接部署gin&#xff08;跳过运行容器时因为挂载文件可能会出现的问题&#xff09; 文章目的是什么 假设我们学习了 go 语言&#xff0c;在 Windows(本…

精选硬件连通性测试工具:企业如何做出明智选择

在当今数字化的商业环境中&#xff0c;企业的硬件连通性至关重要。选择适用的硬件连通性测试工具是确保网络和设备协同工作的关键一步。本文将探讨企业在选择硬件连通性测试工具时应考虑的关键因素&#xff0c;以帮助其做出明智的决策。 1. 功能全面性&#xff1a;首要考虑因素…

PHP微信朋友圈广告植入源码 +提供高效的广告植入解决方案,助力微信朋友圈广告推广

源码介绍 可以无限制帮用户开户&#xff0c;也可以理解为多用户版。 可以管理用户发布文章条数&#xff0c;也可以无限制发布。 用户可以上传多个广告&#xff0c;每个广告分别进行统计展示及点击。 用户一键植入&#xff0c;不用粘贴网址&#xff0c;每篇文章会 分别统计展示…

Peter算法小课堂—简单建模(3)

国王的奖赏系列 国王的奖赏1 题目描述&#xff1a; 你作为战斗英雄得到国王的奖赏&#xff0c;可以在地图上选一块土地。地图里共n*m格土地&#xff0c;第x行第y列的土地格子里标记着d[x][y]的整数价值&#xff0c;可能出现负数。国王让你选择若干列土地&#xff0c;只要是连…

车载以太网笔记

文章目录 以太网协议分层协议中间设备子网掩码物理层测试内容比较杂,后续会整理。 以太网协议分层 协议 中间设备