一文看懂 Linux 内核,清晰明了

Linux内核预备工作

理解Linux内核最好预备的知识点:懂C语言

懂一点操作系统的知识

熟悉少量相关算法

懂计算机体系结构

Linux内核的特点:

结合了 unix 操作系统的一些基础概念。

Linux内核的任务:

1. 从技术层面讲,内核是硬件与软件之间的一个中间层。作用是将应用层序的请求传递给硬件,并充当底层驱动程序,对系统中的各种设备和组件进行寻址。

2. 从应用程序的层面讲,应用程序与硬件没有联系,只与内核有联系,内核是应用程序知道的层次中的最底层。在实际工作中内核抽象了相关细节。

3. 内核是一个资源管理程序。负责将可用的共享资源(CPU时间、磁盘空间、网络连接等)分配得到各个系统进程。

4. 内核就像一个库,提供了一组面向系统的命令。系统调用对于应用程序来说,就像调用普通函数一样。

内核实现策略:

1. 微内核。最基本的功能由中央内核(微内核)实现。所有其他的功能都委托给一些独立进程,这些进程通过明确定义的通信接口与中心内核通信。

2. 宏内核。内核的所有代码,包括子系统(如内存管理、文件管理、设备驱动程序)都打包到一个文件中。内核中的每一个函数都可以访问到内核中所有其他部分。目前支持模块的动态装卸(裁剪)。Linux内核就是基于这个策略实现的。

哪些地方用到了内核机制?

1. 进程(在cpu的虚拟内存中分配地址空间,各个进程的地址空间完全独立;同时执行的进程数最多不超过cpu数目)之间进行通 信,需要使用特定的内核机制。

2. 进程间切换(同时执行的进程数最多不超过cpu数目),也需要用到内核机制。进程切换也需要像 FreeRTOS 任务切换一样保存状态,并将进程置于闲置状态/恢复状态。

3. 进程的调度。确认哪个进程运行多长的时间。



Linux进程



1. 采用层次结构,每个进程都依赖于一个父进程。内核启动init程序作为第一个进程。该进程负责进一步的系统初始化操作。init 进程是进程树的根,所有的进程都直接或者间接起源于该进程。

2. 通过pstree命令查询。实际上系统的第一个进程是 systemd,而不是init(这也是疑问点)

3. 系统中每一个进程都有一个唯一标识符(ID),用户(或其他进程)可以使用ID来访问进程。

Linux内核源代码的目录结构

Linux内核源代码包括三个主要部分:

1. 内核核心代码,包括第3章所描述的各个子系统和子模块,以及其它的支撑子系统,例如电源管理、Linux初始化等。

2. 其它非核心代码,例如库文件(因为Linux内核是一个自包含的内核,即内核不依赖其它的任何软件,自己就可以编译通过)、固件集合、KVM(虚拟机技术)等。

3. 编译脚本、配置文件、帮助文档、版权说明等辅助性文件。使用 ls 命令看到的内核源代码的顶层目录结构(Linux kernel 3.10),具体描述如下。

include/--- 内核头文件,需要提供给外部模块(例如用户空间代码)使用。

kernel/--- Linux内核的核心代码,包含了3.2小节所描述的进程调度子系统,以及和进程调度相关的模块。

mm/--- 内存管理子系统(3.3小节)。

fs/--- VFS子系统(3.4小节)。

net/--- 不包括网络设备驱动的网络子系统(3.5小节)。

ipc/--- IPC(进程间通信)子系统。

arch/ --- 体系结构相关的代码,例如 arm, x86 等等。

arch/mach --- 具体 machine/board 相关的代码。

arch/include/asm --- 体系结构相关的头文件。

arch/boot/dts --- 设备树(Device Tree)文件。

init/--- Linux系统启动初始化相关的代码。

block/--- 提供块设备的层次。

sound/--- 音频相关的驱动及子系统,可以看作“音频子系统”。

drivers/--- 设备驱动(在Linux kernel 3.10中,设备驱动占了49.4的代码量)。

lib/--- 实现需要在内核中使用的库函数,例如CRC、FIFO、list、MD5等。

crypto/--- 加密、解密相关的库函数。

security/--- 提供安全特性(SELinux)。

virt/--- 提供虚拟机技术(KVM等)的支持。

usr/--- 用于生成 initramfs 的代码。

firmware/--- 保存用于驱动第三方设备的固件。

samples/--- 一些示例代码。

tools/--- 一些常用工具,如性能剖析、自测试等。

Kconfig, Kbuild, Makefile, scripts/ --- 用于内核编译的配置文件、脚本等。

COPYING --- 版权声明。

MAINTAINERS ---维护者名单。

CREDITS --- Linux主要的贡献者名单。

REPORTING-BUGS --- Bug上报的指南。

Documentation, README --- 帮助、说明文档。

Linux内核体系结构简析

图1 Linux系统层次结构

最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。

Linux 内核可以进一步划分成 3 层。最上面是系统调用接口,它实现了一些基本的功能,例如 read 和 write。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。

Linux 内核实现了很多重要的体系结构属性。在或高或低的层次上,内核被划分为多个子系统。Linux 也可以看作是一个整体,因为它会将所有这些基本服务都集成到内核中。这与微内核的体系结构不同,后者会提供一些基本的服务,例如通信、I/O、内存和进程管理,更具体的服务都是插入到微内核层中的。每种内核都有自己的优点,不过这里并不对此进行讨论。

随着时间的流逝,Linux 内核在内存和 CPU 使用方面具有较高的效率,并且非常稳定。但是对于 Linux 来说,最为有趣的是在这种大小和复杂性的前提下,依然具有良好的可移植性。Linux 编译后可在大量处理器和具有不同体系结构约束和需求的平台上运行。一个例子是 Linux 可以在一个具有内存管理单元(MMU)的处理器上运行,也可以在那些不提供 MMU 的处理器上运行。

Linux 内核的 uClinux 移植提供了对非 MMU 的支持。图2是Linux内核的体系结构

图2 Linux内核体系结构Linux内核的主要组件有:

系统调用接口、进程管理、内存管理、虚拟文件系统、网络协议栈、设备驱动程序、硬件架构的相关代码。

(1)系统调用接口

SCI 层提供了某些机制执行从用户空间到内核的函数调用。正如前面讨论的一样,这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。在 ./linux/kernel 中您可以找到 SCI 的实现,并在 ./linux/arch 中找到依赖于体系结构的部分。

(2)进程管理

进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程 这个术语,不过 Linux 实现并没有区分这两个概念(进程和线程)。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者 POSIX 机制)。进程管理还包括处理活动进程之间共享 CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争 CPU,这种算法都可以在固定时间内进行操作。这种算法就称为 O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。O(1) 调度程序也可以支持多处理器(称为对称多处理器或 SMP)。您可以在 ./linux/kernel 中找到进程管理的源代码,在 ./linux/arch 中可以找到依赖于体系结构的源代码。

(3)内存管理

内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页 方式进行管理的(对于大部分体系结构来说都是 4KB)。

Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。不过内存管理要管理的可不止 4KB 缓冲区。Linux 提供了对 4KB 缓冲区的抽象,例如 slab 分配器。这种内存管理模式使用 4KB 缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在 ./linux/mm 中找到。

(4)虚拟文件系统

虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层(请参看图4)。

图3 Linux文件系统层次结构在 VFS 上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。

(5)网络协议栈

网络协议栈在设计上遵循模拟协议本身的分层体系结构。回想一下,Internet Protocol (IP) 是传输协议(通常称为传输控制协议或 TCP)下面的核心网络层协议。TCP 上面是 socket 层,它是通过 SCI 进行调用的。socket 层是网络子系统的标准 API,它为各种网络协议提供了一个用户接口。从原始帧访问到 IP 协议数据单元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。内核中网络源代码可以在 ./linux/net 中找到。

(6)设备驱动程序

Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth、I2C、serial 等。设备驱动程序的代码可以在 ./linux/drivers 中找到。

(7)依赖体系结构的代码

尽管 Linux 很大程度上独立于所运行的体系结构,但是有些元素则必须考虑体系结构才能正常操作并实现更高效率。./linux/arch 子目录定义了内核源代码中依赖于体系结构的部分,其中包含了各种特定于体系结构的子目录(共同组成了 BSP)。对于一个典型的桌面系统来说,使用的是 x86 目录。每个体系结构子目录都包含了很多其他子目录,每个子目录都关注内核中的一个特定方面,例如引导、内核、内存管理等。这些依赖体系结构的代码可以在 ./linux/arch 中找到。 如果 Linux 内核的可移植性和效率还不够好,Linux 还提供了其他一些特性,它们无法划分到上面的分类中。作为一个生产操作系统和开源软件,Linux 是测试新协议及其增强的良好平台。Linux 支持大量网络协议,包括典型的 TCP/IP,以及高速网络的扩展(大于 1 Gigabit Ethernet [GbE] 和 10 GbE)。Linux 也可以支持诸如流控制传输协议(SCTP)之类的协议,它提供了很多比 TCP 更高级的特性(是传输层协议的接替者)。Linux 还是一个动态内核,支持动态添加或删除软件组件。被称为动态可加载内核模块,它们可以在引导时根据需要(当前特定设备需要这个模块)或在任何时候由用户插入。

Linux 最新的一个增强是可以用作其他操作系统的操作系统(称为系统管理程序)。最近,对内核进行了修改,称为基于内核的虚拟机(KVM)。这个修改为用户空间启用了一个新的接口,它可以允许其他操作系统在启用了 KVM 的内核之上运行。除了运行 Linux 的其他实例之外, Microsoft Windows 也可以进行虚拟化。惟一的限制是底层处理器必须支持新的虚拟化指令。

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

Linux体系结构和内核结构区别

1.当被问到Linux体系结构(就是Linux系统是怎么构成的)时,我们可以参照下图这么回答:从大的方面讲,Linux体系结构可以分为两块:

(1)用户空间:用户空间中又包含了,用户的应用程序,C库。

(2)内核空间:内核空间包括,系统调用,内核,以及与平台架构相关的代码。

2.Linux体系结构要分成用户空间和内核空间的原因:

1)现代CPU通常都实现了不同的工作模式,以ARM为例:ARM实现了 7 种工作模式,不同模式下 CPU 可以执行的指令或者访问的寄存器不同:

(1)用户模式 usr

(2)系统模式 sys

(3)管理模式 svc

(4)快速中断 fiq

(5)外部中断 irq

(6)数据访问终止 abt

(7)未定义指令异常以

(2)X86为例:X86实现了 4 个不同级别的权限,Ring0—Ring3;Ring0下可以执行特权指令,可以访问 IO 设备;Ring3 则有很多的限制。

2)所以,Linux从CPU的角度出发,为了保护内核的安全,把系统分成了2部分;

3.用户空间和内核空间是程序执行的两种不同状态,我们可以通过“系统调用”和“硬件中断“来完成用户空间到内核空间的转移。

4.Linux的内核结构(注意区分LInux体系结构和Linux内核结构)

Linux 驱动的 platform 机制

Linux 的这种 platform driver 机制和传统的 device_driver 机制相比,一个十分明显的优势在于 platform 机制将本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过 platform_device 提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性。下面是 SPI 驱动层次示意图,Linux 中的 SPI 总线可理解为 SPI 控制器引出的总线:

和传统的驱动一样,platform机制也分为三个步骤:

1、总线注册阶段:内核启动初始化时的main.c文件中的kernel_init()→do_basic_setup()→driver_init()→platform_bus_init()→bus_register(&platform_bus_type),注册了一条platform总线(虚拟总线,platform_bus)。

2、添加设备阶段:

设备注册的时候Platform_device_register()→platform_device_add()→(pdev→dev.bus = &platform_bus_type)→device_add(),就这样把设备给挂到虚拟的总线上。

3、驱动注册阶段:Platform_driver_register()→driver_register()→bus_add_driver()→driver_attach()→bus_for_each_dev(), 对在每个挂在虚拟的platform bus的设备作__driver_attach()→driver_probe_device(),判断drv→bus→match()是否执行成功,此时通过指针执行platform_match→strncmp(pdev→name , drv→name , BUS_ID_SIZE),如果相符就调用really_probe(实际就是执行相应设备的platform_driver→probe(platform_device)。)开始真正的探测,如果probe成功,则绑定设备到该驱动。从上面可以看出,platform机制最后还是调用了bus_register() , device_add() , driver_register() 这三个关键的函数。下面看几个结构体:

struct platform_device  (/include/linux/Platform_device.h)
{
  const char     * name;
  int            id;
  struct device  dev;
  u32             num_resources;
  struct resource  * resource;
};

Platform_device 结构体描述了一个 platform 结构的设备,在其中包含了一般设备的结构体 struct device dev; 设备的资源结构体 struct resource * resource;还有设备的名字 const char * name。(注意,这个名字一定要和后面platform_driver.driver àname相同,原因会在后面说明。)

该结构体中最重要的就是resource结构,这也是之所以引入platform机制的原因。

struct resource     ( /include/linux/ioport.h)
{
  resource_size_t start;
  resource_size_t end;
  const char *name;
  unsigned long flags;
  struct resource *parent, *sibling, *child;
};

其中 flags 表示该资源的类型,start 和 end 分别表示该资源的起始地址和结束地址(/include/linux/Platform_device.h):

struct platform_driver 
{
  int (*probe)(struct platform_device *);
  int (*remove)(struct platform_device *);
  void (*shutdown)(struct platform_device *);
  int (*suspend)(struct platform_device *, pm_message_t state);
  int (*suspend_late)(struct platform_device *, pm_message_t state);
  int (*resume_early)(struct platform_device *);
  int (*resume)(struct platform_device *);
  struct device_driver driver;
};

Platform_driver 结构体描述了一个 platform 结构的驱动。其中除了一些函数指针外,还有一个一般驱动的 device_driver 结构。

名字要一致的原因:

上面说的驱动在注册的时候会调用函数 bus_for_each_dev(), 对在每个挂在虚拟的platform bus 的设备作__driver_attach()→driver_probe_device(),在此函数中会对dev和drv做初步的匹配,调用的是drv->bus->match所指向的函数。

platform_driver_register 函数中 drv->driver.bus = &platform_bus_type,所以 drv->bus->match 就为 platform_bus_type→match,为 platform_match 函数,该函数如下:

static int platform_match(struct device * dev, struct device_driver * drv)
{
  struct platform_device *pdev = container_of(dev, struct platform_device, dev);

  return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}

是比较 dev 和 drv 的 name,相同则会进入 really_probe() 函数,从而进入自己写的 probe 函数做进一步的匹配。所以 dev→name 和 driver→drv→name 在初始化时一定要填一样的。

不同类型的驱动,其 match 函数是不一样的,这个 platform 的驱动,比较的是 dev 和drv 的名字,还记得 usb 类驱动里的 match 吗?它比较的是 Product ID 和 Vendor ID。

个人总结 Platform 机制的好处:

1、提供 platform_bus_type 类型的总线,把那些不是总线型的soc设备都添加到这条虚拟总线上。使得,总线——设备——驱动的模式可以得到普及。

2、提供platform_device和platform_driver类型的数据结构,将传统的device和driver数据结构嵌入其中,并且加入resource成员,以便于和Open Firmware这种动态传递设备资源的新型bootloader和kernel 接轨。

原文作者:【一起学嵌入式

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

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

相关文章

制作图片马

准备一张图片和一句话木马 打开cmd copy 图片/b文件 新的图片的名字 然后就自动生成了

Excel——多列合并成一列的4种方法

Excel怎么将多列内容合并成一列? 怎么将多个单元格的内容连接起来放在一个单元格里? 比如下图,要将B、C、D列的内容,合并成E列那样,该怎么做呢? △图1 本文中,高潜老师将给大家介绍 4种 将多…

随机链表的复制[中等]

优质博文:IT-BLOG-CN 一、题目 给你一个长度为n的链表,每个节点包含一个额外增加的随机指针random,该指针可以指向链表中的任何节点或空节点。构造这个链表的深拷贝。深拷贝应该正好由n个全新节点组成,其中每个新节点的值都设为…

DAPP开发【09】NFT交易市场开发(hardhat测试)

测试文件下新建market.js文件 扁平化,将所有依赖放在tmp.sol,可以去给他人使用 npx hardhat flatten > tmp.sol 测试文件 const {expect} require(chai); const {ethers} require(hardhat);describe(Market,async function(){//定义三个合约&a…

BL121EN:IEC 61850到OPC UA的即插即用无缝转换解决方案

添加图片注释,不超过 140 字(可选) 在当今快速发展的工业自动化领域,实现不同通信协议之间的无缝连接是提高系统集成度、数据共享和设备互操作性的关键。钡铼技术(Bay-Tech)BL121EN硬网关应运而生&#xf…

vue3项目中使用iconfont图标

vue3项目中使用iconfont图标 写前端项目时,经常要用到iconfont图标,我最原始的方法是吧iconfont图标下载为png/svg文件,然后在文件中作为资源引入,后来发现这么搞太不专业了 记录一下相对比较靠谱的使用方法 1.在iconfont中找到…

【Spring Boot】如何在IntelliJ IDEA中由同一份spring boot源码运行多个不同端口的实例

我们需要使用一个服务有多个实例的测试场景,那么我们就需要在IntelliJ IDEA中通过不同的端口运行不同的实例,并且运行时的源代码是一样的,那么我们可以在IntelliJ IDEA这样操作,接下来以UserApplication服务为例: 复制…

【MySQL】基本安装配置

1 基础知识 1.1 MySQL安装 下载地址:https://dev.mysql.com/downloads/mysql/ 1.1.1 安装过程 配置环境变量(和配置Java8的环境变量如出一辙)在MySQL解压文件夹下,导入my.ini文件,与bin目录同级,具体文…

Linux4.8、环境变量续

个人主页:Lei宝啊 愿所有美好如期而遇 前言 如果对环境变量没有基本的理解,那么建议先看完这篇文章:环境变量https://blog.csdn.net/m0_74824254/article/details/134661113?spm1001.2014.3001.5501 环境变量与本地变量区别 使用export设…

二百一十一、Flume——Flume实时采集Linux中的Hive日志写入到HDFS中(亲测、附截图)

一、目的 为了实现用Flume实时采集Hive的操作日志到HDFS中,于是进行了一场实验 二、前期准备 (一)安装好Hadoop、Hive、Flume等工具 (二)查看Hive的日志在Linux系统中的文件路径 [roothurys23 conf]# find / -name…

PostGIS学习教程十:空间索引

PostGIS学习教程十:空间索引 回想一下,空间索引是空间数据库的三个关键特性之一。空间索引使得使用空间数据库存储大型数据集成为可能。在没有空间索引的情况下,对要素的任何搜索都需要对数据库中的每条记录进行"顺序扫描"。索引通…

AI生成视频-Pika

背景介绍 Pika 是一个使用 AI 生成和编辑视频的平台。它致力于通过 AI 技术使视频制作变得简单和无障碍。 Pika 1.0 是 Pika 的一个重大产品升级,包含了一个新的 AI 模型,可以在各种风格下生成和编辑视频,如 3D 动画,动漫,卡通和电影风格。…

HTTP会话技术---Cookie、Session和Token介绍及它们在JavaWeb中的使用

当涉及到Web应用程序的身份验证和状态管理时,我们通常会使用到Cookie、Session和Token这些会话技术。下面是对它们的介绍,并在JavaWeb中的示例 Cookie(HTTP Cookie) Cookie是一种存储在用户浏览器中的小型文本文件,由…

Elasticsearch:什么是情感分析?

情感分析的定义 情感分析应用自然语言处理(NLP)、计算语言学和机器学习来识别数字文本的情感基调。 这使得组织能够识别对其品牌、产品、服务或想法的积极、中立或消极情绪。 最终,它使企业能够更好地了解客户,从而为企业提供可行…

题目:区间更新(蓝桥OJ 3291)

题目描述&#xff1a; 解题思路&#xff1a; 差分模板题。 题解&#xff1a; #include<bits/stdc.h> using namespace std;const int N 1e5 10; int a[N], diff[N] ;//数组的大小不可能开到大于1e9int res(int n, int m) {for(int i 1; i < n; i)cin >&g…

Linux使用root用户安装完MySQL软件后,配置MySQL这个普通用户登录

在 Linux 系统中&#xff0c;当您使用 root 用户安装 MySQL 后&#xff0c;系统会自动创建一个名为 mysql 的系统用户。这个 mysql 用户主要用于管理 MySQL 服务的运行&#xff0c;通常是没有登录系统的权限的。如果您希望使这个 mysql 用户能够登录到系统&#xff0c;您需要设…

GPC-虚拟主平台(VPP)概述

VPP: Virtual Primary Platform 虚拟主平台 2021年12月&#xff0c;GP发布了VPP 2.0。 随着安全芯片生态系统的发展&#xff0c;集成已成为一个显著的趋势。为了支持这一点&#xff0c;GP已经定义了虚拟主平台&#xff08;VPP&#xff09; 规范集概述并标准化了新的SE形式因素…

解决HTTP错误500.19 - internal server error -内部服务器错误的终极指南

在开发和维护网络应用程序时&#xff0c;难免会遇到各种HTTP错误代码。其中&#xff0c;HTTP错误500.19 - 内部服务器错误可谓是最令人头痛的问题之一。当你的应用程序遇到这个错误时&#xff0c;它似乎就像一道墙壁&#xff0c;挡住了你前进的道路。但别担心&#xff0c;本篇技…

极兔快递查询,极兔快递单号查询,将其中的退回件筛选出来

批量查询极兔快递单号的物流信息&#xff0c;将其中的退回件筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 极兔快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左上角的…

Python OS模块常用方法整理

os模块包含了普遍的操作系统和文件目录方法 引入类库 首先需要引入类库 import os 常用方法 OS模块方法 获取操作系统类型 nt->window:Microsoft Windows NT posix->Linux/Mac OS: Portable Operating System Interface of UNIX&#xff08;可移植操作系统接口&…