Linux学习:文件描述符fd

news2024/11/25 4:04:01

目录

  • 1. 引子
  • 2. C语言文件接口
    • 2.1 文件的打开与关闭的操作
    • 2.2 文件写入读取操作
    • 2.3 当前路径
  • 3. 文件I/O操作与系统调用
    • 3.1 程序默认打开的文件流
    • 3.2 操作系统访问文件的系统调用接口
      • 3.2.1 文件打开与关闭操作
      • 3.2.2 写入与读取操作
  • 4. 什么是文件描述符fd
    • 4.1 进程与文件的关系
    • 4.2 C语言对文件fd与接口封装载使用的意义
    • 4.3 Linux操作系统下一切皆文件的设计理念
  • 5. 文件fd的分配规则与重定向
  • 6. C语言库缓冲区
    • 6.1 C语言库缓冲区的存在意义
    • 6.2 C语言缓冲区的物理位置与存在证明

1. 引子

  1. 在前面关于文件的学习中,我们只有文件由内容与属性两部分构成,因此,空文件只是文件内容为空仍然包含着其的属性信息,所以大小并不为空。
  2. 在C语言的学习中,我们学习过文件操作相关的接口,在对文件操作进行操作前每次都需要使用fopen函数的指定模式打开对应需要修改的文件。而在操作系统中,我们想要编辑修改文件时,也要提前需要将对应的文件使用编辑器打开。那么,
    <1> 为什么每每当我们想要访问文件都要将文件打开呢?
    <2> 而这一文件的打开操作又具体做了些什么?
    <3> 文件又具体是由谁来打开,谁来修改的呢?
  1. 系统的文件常态下都存储在磁盘之中,而在磁盘中的文件无法直接进行修改(CPU只处理内存中的数据),所以,每当要对磁盘中的文件进行修改都必须要将其加载至内存中,这一操作我们就称之为文件的打开。
  1. 修改文件的内容,我们可以通过C语言中文件操作相关的接口来实现,而这些函数的使用都是以代码的方式被编写在程序之中,此后再将程序编译生成可执行程序加载到内存中成为进程。当进程被执行到相应二进制指令时,才会对文件进行指定打开修改等操作。
    <1> 因此,我们可以理解为是进程打开了文件,对文件进行了相应一系列的操作。
    <2> 一个进程可以打开多个文件
  1. 综上所述,我们可以下定一个如下结论:一定时间段内,系统内会存在多个进程,可能同时更多被打开的文件。
  1. 操作系统是计算机软硬资源的管理者,这些被打开的文件也是计算机资源,因而操作系统也必然对其进行管理。操作系统对计算机资源的管理方式与里面为先描述,再组织,所以,可以明确的是,内核中,一定存在着描述被打开文件的结构体,并有着使用其定义的对象
  1. 因为操作系统的描述组织的管理方式,所以我们对文件相关知识的学习,实质上就是研究进程与文件的关系。(struct task_struct 与 struct file)
  1. 操作系统中,并给所有文件都被打开了,文件根据所处位置的不同,可以区分为两种:
    <1> 内存文件(被打开的文件)
    <2> 磁盘中的文件(没有被打开的文件)

2. C语言文件接口

2.1 文件的打开与关闭的操作

  1. fopen(打开)
FILE* fopen(const char* filename, const char* mode);//stdio.h
  1. fopen函数第二个参数决定了被打开文件的打开模式,常用有如下三种:
  2. "w"模式(写入模式)
    <1> 若文件不存在,则会在当前目录中新建此文件。
    <2> 打开文件后,会将文件原有内容清空,从文件开头写入
    <3> 输出 >重定向的被指就是向文件中写入
  3. "a"模式(追加模式)
    <1> 本质上也是对文件进行写入,只是不会将文件内容清空
    <2> 从文件结尾开始写入
    <3> 追加>>重定向
  4. "r"模式(读取模式)
  1. fclose(关闭)
int fclose(FILE* stream);//stdio.h
  1. 关闭指定的已打开的文件
  2. 关闭成功返回0,关闭失败返回EOF

2.2 文件写入读取操作

  1. fputs
int fputs ( const char* str, FILE* stream );
  1. 以字符串的形式向指定文件中写入
  2. 此种写入方式可以识别出字符串,以字符串为单位,遇到字符串结束标志\0就会停止写入
#include <stdio.h>

int main()
{
	FILE* fp = fopen("log.txt", "w");
	
	char buf[] = "hello\0 world";
	fputs(buf, fp);

	fclose(fp);
	
	return 0;
}

在这里插入图片描述
2. fwrite

size_t fwrite ( const void* ptr, size_t size, size_t count, FILE* stream );
  1. 参数ptr:存储需要写入数据空间的地址
  2. 参数size:写入数据的基本单位大小(字节)
  3. 参数count:一次写入多少个基本单位
  4. 以二进制流的形式进行写入,写入时需要指定写入数据大小
  5. C语言中,将数据视作一条"河流",从一个设备流向另一个设备
#include <stdio.h>

int main()
{
	FILE* fp = fopen("log.txt", "w");
	
	char buf[] = "hello\0 world";
	fwrite(buf, sizeof(buf), 1, fp);

	fclose(fp);
	
	return 0;
}

在这里插入图片描述

2.3 当前路径

  1. 什么叫做进程的当前路径?
    <1> 在进程被执行时,会在系统目录proc中创建一个相应的临时目录,目录名为进程的pid码,其中记录着诸多这一进程的相关信息。
    <2> 进程启动时会记录当前所处的路径,进程目录中的cwd对应标识信息。

在这里插入图片描述

  1. C语言fopen 接口以"w"模式打开一个文件,若此文件不存在则会在当前路径下创建一个同名文件。
    <1> 进程的当前路径默认为程序所在目录
    <2> 当前路径可以被改变,我们可以通过chdir函数来改变进程的当前路径
    <3> 进程与文件之间有着莫大的关系,进程的路径就决定了新建文件的位置
#include <stdio.h>
#include <unistd.h>

int main()
{
	chdir("./dir");
	FILE* fp = fopen("log.txt", "w");
	
	fclose(fp);

	return 0;
}

在这里插入图片描述

3. 文件I/O操作与系统调用

3.1 程序默认打开的文件流

  1. 在Linux操作系统下,一切皆是文件,我们平时用来输入信息的键盘,查看打印信息的显示器也不例外。因此,硬件设备的数据输入输出,我们就可以将其理解为向相应的文件中写入或者读取数据。
  1. C语言文件操作的相关接口中,fopen函数的返回值为一个类型为FILE的结构体指针,这个FILE类型即为C语言概念中的描述文件的类型。而C语言库中默认存在着三个输入输出相关的文件流,这三个文件流会在进程运行的时候默认被打开,分别为:
    <1> 标准输入:stdin,对应硬件设备:键盘
    <2> 标准输出:stdout,对应硬件设备:显示器
    <3> 标准错误:stderr,对应硬件设备:显示器
  1. 标准输入,输出相关C语言函数:
    <1> 标准输出:fputcfprintffwrite
    <2> 标准输入:scanffscanffread

3.2 操作系统访问文件的系统调用接口

  1. <1> 文件的I/O操作必定要与硬件设备产生关联,诸如显示器,磁盘,键盘等。
    <2> 而我们是无法直接操控访问计算机的硬件设备的,必须要通过操作系统贯穿整个计算机软硬件层次结构才可以实现。
    <3> 也就是说,即使我们是通过调用C语言库函数来实现文件操作的,实质上也是需要通过操作系统来实现的。
    <4> 通过操作系统来实现文件操作的方式为使用操作系统提供的系统调用接口。
  1. 综上所述,我们也就可以得知C语言对应的文件操作函数在底层一定封装了相应操作系统的系统调用接口,接下来进行相关的了解与学习。

3.2.1 文件打开与关闭操作

  1. open系统调用接口
//头文件sys/types.h,sys/stat.h,fcntl.h
int open(const char* pathname, int flag);
int open(const char* pathname, int flag, mode_t mode);
  1. 参数pathname:打开文件的所在路径
  2. 参数flag:标志位,通过传递不同的标志为可以以不同的访问方式打开文件
  3. 参数mode:设置文件的初始权限位,可以使用系统接口umask来提前设置创建文件的权限掩码
  4. 返回文件描述符fd,数据类型为整形
  1. flag标志位的常用参数
  1. O_RONLY,只读
  2. O_WRONLY,只写
  3. O_RDWR,读写
  4. O_TRUNC,清空文件,覆盖式写入
  5. O_APPEND,向文件结尾写入,追加
  6. O_CREAT,创建文件
  1. 系统所给出的flag参数实质上为一个个定义好的宏,flag参数的类型为int,其有着32个bit位。
    <1> 这些宏都是32个bit位中只有一位为1的int类型数据,并且它们的含1bit位都互相错位
    <2> 通过此种位操作宏定义与按位与|的方式,可以达到一次性传递多个标志位参数的效果,Linux操作系统中常用。
#define ONE 1
#define TWO (1<<1)
#define THREE (1<<2)
#define FOUR (1<<3)
#define FIVE (1<<5)
 
void mytest(int flag)
{
	if(flag & ONE)
		printf("this is ONE\n");
	if(flag & TWO)
		printf("this is TWO\n");
	if(flag & THREE)
		printf("this is THREE\n");
	if(flag & FOUR)
		printf("this is FOUR\n");
	if(flag & FIVE)
		printf("this is FIVE\n");
 }
 
 int main()
 {
	mytest(ONE);
	printf("----------------------------------\n");
	mytest(ONE | TWO);
	printf("----------------------------------\n");
	mytest(ONE | TWO | THREE);
	printf("----------------------------------\n");
	mytest(ONE | TWO | THREE | FOUR);
	printf("----------------------------------\n");                                                                                                                                    
	mytest(ONE | TWO | THREE | FOUR | FIVE); 
 
    return 0;
}

在这里插入图片描述
3. open系统调用接口的使用方式

int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
//模拟fwrite的"w"模式,mode参数传递三位8进制数,文件权限位默认设置为111 111 111

int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666);
//模拟fwrite的"a"模式

int fd = open("log.txt", O_RONLY, 0666);
//模拟fwrite的"r"模式
  1. close系统调用接口
//头文件unistd.h
int close(int fd);
  1. 传递参数文件fd关闭指定文件
  2. 关闭成功返回0,关闭失败返回-1

3.2.2 写入与读取操作

  1. write系统调用接口
//头文件unistd.h
ssize_t write(int fd, const void* buf, size_t count);
  1. 参数fd:文件描述符
  2. 参数buf:写入数据存储地址,缓冲区
  3. 参数count:写入数据的大小,单位字节
  4. 返回值为signed size_t,有符号整形,写入成功返回0,写入失败返回-1
  1. read系统调用接口
ssize_t read(int fd, const void* buf, size_t count);
  1. 参数fd:文件描述符,指定读取内容的文件
  2. 参数buf:读取的内容存储空间的地址
  3. 参数count:读取多少个字节
  4. 返回值ssize_t,有符号整形,读取成功返回读取了多少个字节,读取失败返回-1

4. 什么是文件描述符fd

4.1 进程与文件的关系

  1. 从上面我们新学习到的Linux系统文件相关系统调用接口,可以看出其对文件进行的一系列操作都是通过open接口的返回值fd来实现的,通过fd来找到对应的文件进行写入,读取,关闭等操作。
  2. fd是一个整形数据,其被称作文件描述符,可是这一个整形数据是如何标识表明不同文件的呢,打开不同文件时其的值又有什么不同吗?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
	umask(0);
	int fd1 = open("log1.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
	int fd2 = open("log2.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
	int fd3 = open("log3.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
	int fd4 = open("log4.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
	int fd5 = open("log5.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);

	printf("fd1 = %d\n", fd1);
	printf("fd2 = %d\n", fd2);
	printf("fd3 = %d\n", fd3);
	printf("fd4 = %d\n", fd4);
	printf("fd5 = %d\n", fd5);

	close(fd1);
	close(fd2);
	close(fd3);
	close(fd4);
	close(fd5);

	return 0;
}

在这里插入图片描述

  1. 我们可以发现,打开文件的返回值fd是从3开始递增的连续整数
    <1> 这又代表着什么意义呢?
    <2> 返回值有为什么是从3开始的整数而不是0?
    <2> 如果有3之前的返回值整数,那么它们是在哪里被使用了呢?
  1. <1> 系统调用接口open给我们返回值,文件描述符fd,其是用来标识进程内打开的各个文件,我们需要借助其对指定文件进行访问。
    <2> 因为对底层硬件的访问必要借助操作系统贯穿整个计算机软硬件层次结构,所以C语言lib也必然在底层封装了操作系统提供的系统调用接口。
    <3> C语言库中文件操作相关的函数,fopen打开文件的函数其返回值是一个FILE类型的指针,这一C语言自定义用来描述文件的数据类型其内也必定封装了文件描述符fd。
    <4> 在一个进程中,每当其被执行时,就会默认帮我们打开3个常用的文件流,stdinstdoutstderr,也正是这三个打开的文件占用了文件fd返回值的前三位。
#include <stdio.h>

int main()
{
	//stdio.h头文件中存在这这三个FILE类型的全局变量
	//其中的成员变量fileno正对应着文件描述符fd
	printf("%d\n", stdin->fileno);
	printf("%d\n", stdout->fileno);
	printf("%d\n", stderr->fileno);

	return 0;
}

在这里插入图片描述

  1. <1> 从0开始的fd返回值,这一组返回值其的数据特征极其类似于数组的下标
    <2> 系统调用接口为什么又仅仅能通过这一整形数据就找到文件
    <3> fd又是如何表示描述各个被打开文件的,接下来,就让我们对进程与打开文件的底层数据结构与关系进行了解与学习。
  1. 我们通过前面的学习可以知道,进程由内核数据结构,代码与数据组成。
    <1>其中操作系统对一个进程进行控制,主要就是通过其的内核数据结构进程PCB(struct task_struct)来达成的, 这一数据结构使用来记录描述各种进程相关信息的。
    <2> 而对于文件操作系统也采用了类似的方式,创建一个数据结构用来描述文件的各种属性信息,并通过调整控制这些信息来达到控制文件效果。

在这里插入图片描述

4.2 C语言对文件fd与接口封装载使用的意义

  1. 为什么已经有了系统调用接口与可以直接找到文件的描述符fd,C语言还要对接口与文件fd进行封装后再使用?
  2. 不同的操作系统对文件管理的方式都会有所不同,提供给用户的文件相关系统调用接口也都有所不同
  3. 因此,直接使用系统调用接口和与其提供相关的文件描述符fd,都会使得C语言提供的接口不具备跨平台性,可移植性性
  4. C语言库通过这种封装的方式,将各个操作系统底层实现的差异通过库的方式屏蔽掉,这样我们所编写的代码就可以在各种平台上编译运行

4.3 Linux操作系统下一切皆文件的设计理念

  1. 从初识Linux操作系统时,就了解到了Linux一切皆文件的设计哲学,通过这种统一的描述方式,将计算机中的各种软硬件资源都以文件的方式描述,组织,管理起来。
  2. 可是,我们对此并没有实感,也并不清楚Linux操作系统是如何去做的,为此又做了哪些工作?
  3. 接下来,就让我们通过Linux中对硬件设备的文件描述与管理方式来初步理解一下,Linux下一切皆文件的设计理念

在这里插入图片描述

5. 文件fd的分配规则与重定向

  1. 我们运行进程时,会默认打开三个标准输入输出文件流
  2. 我们通过上面对于文件相关底层数据结构的学习得知,文件fd的本质为数组的下标,以fd为索引取对应的文件指针数组中去找到对应的进程打开的文件
  3. 对于这些先后打开的文件,它们在对应进程的文件指针数组中的分配方式为:
    <1> 当前最小的没有被使用的数组下标,分配给最新打开的文件
  1. C语言库函数printf,其是向标准输出文件流中写入数据,在底层实现上它的机制十分简单
    <1> 因此,在进程运行时,stdout会被默认打开并分配到文件指针数组fd为1的下标位置
    <2> 所以,printf会默认项文件指针数组下标为1位置所对应的文件写入
    <3> 着也意味着无论此位置上对应的是否为stdout,其都会进行写入,因此,我们可以进行如下操作
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
	close(1);
	open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);
	//改变打开模式,即可调整为追加重定向
	//open("log.txt", O_WRONLY|O_CREAT|O_APPEN, 0666);
	printf("hello world!\n");
	//write,fprintf,fwrite指定文件
	
	//以读取模式打开,O_RDONLY,输入重定向
	//scanf
	//read,fscanf,fread

	return 0;
}

在这里插入图片描述

  1. 如上的操作,实质上也就是输出重定向的原理,改变写入数据的文件流向,除开上述此种方式外,还有另外一种更加便捷的方式:
    <1> 将需要需要接收数据的文件指针拷贝覆盖至指定位置
    <2> Linux操作系统提供了相应接口,其可以很好处理拷贝操作附带产生的一系列问题
//头文件fcntl.h,unistd.h
int dup2(int oldfd, init newfd);
  1. 系统调用接口dup2,将oldfd下标对应的文件指针,拷贝至newfd位置
int main()
{
	int fd = open("log.txt", O_RDONLY);
	dup2(fd, 0);
	char buf[1024] = {0};
	scanf("%s", buf);
	printf("%s\n", buf);

	return 0;
}

在这里插入图片描述

  1. 补充:在当前目录寻找指定名称的文件find . -name [文件名]

6. C语言库缓冲区

6.1 C语言库缓冲区的存在意义

#include <stdio.h>
#include <unistd.h>

int main()
{
	printf("hello Linux!");
	sleep(3);

	return 0;
}

在这里插入图片描述

  1. 由上述代码的运行结果可以看到,我们向显示器上打印的内容没有被立即写入打印,而是等待3秒后进程运行结束才被写入,这是怎么回事呢?
  2. C语言中存在着一块缓冲区,这块缓冲区是用来存储使用C语言接口写入各个文件中数据的。
  1. 为什么要存在这一语言级别的缓冲区呢?
    <1> 每次将数据写入操作系统中的文件缓冲区,本身这一过程中就会有着不小的系统的开销,而时时写入,频繁拷贝的方式无疑会大大增加系统开销。
    <2> 因此,C语言库中就设计了这一语言级别的缓冲区,先将需要写入的数据统一暂存在缓存中,等待积累了一定的数据量再统一刷新缓冲区进行拷贝。
    <3> 这样的方式本质上是一种用空间换时间的设计技巧,这样不仅提升了数据拷贝的效率减少了消耗,并且加快了C语言接口调用速度。
  1. C语言缓冲区的刷新方式:
    <1> 无刷新,无缓冲
    <2> 行刷新(向显示器写入)
    <3> 全缓冲,全部刷新(普通文件写入)
    特殊情况:
    <1> 主动强制刷新(fflush)
    <2> 进程退出时,主动刷新

6.2 C语言缓冲区的物理位置与存在证明

  1. 技术层面上,我们一直所说的缓冲区与操作系统中的内核缓冲没有关系,是语言层面的缓冲区,C语言自带。
  2. 那么,这一块缓冲区与物理空间上究竟存在于哪里呢?
    <1> 使用C语言文件操作相关接口打开文件时,其会返回一个描述文件相关信息的FILE结构体指针
    <2> 这一结构体内不仅仅包含着打开文件的相关信息,并且还为我们开辟以一块用来存储向此文件写入数据的缓存区(FILE结构体中
  1. 验证此块C语言级别缓冲区存在,且缺位独属于C语言的语言级别缓冲区:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main()
{
	char buf1[] = "this is buf1\n";
	char buf2[] = "this is buf2\n";
	char buf3[] = "this is buf3\n";
	
	write(1, buf1, strlen(buf1));
	fwrite(buf2, strlen(buf2), 1, stdout);
	fprintf("%s", buf3, stdout);

	fork();

	return 0;
}

在这里插入图片描述

  1. 根据运行结果论证:
    <1> write为系统调用接口,其会将数据直接写入到系统内核中的文件缓冲区
    <2> fwrite与fprintf为C语言库函数,它们会将数据先写入C语言缓冲再随后刷新
    <3> 向显示器写入时,C语言缓冲区的刷新方式为行刷新,向普通文件写入时则是全刷新
    <4> fork创建的子进程会继承父进程的全部数据与代码,也会继承父进程执行流,即父进程执行至那一条语句,那么其也从那一条语句开始执行
    <5> 父子进程谁先执行并不确定,这一点由调用器决定,单子进程必定比父进程先结束,当子进程结束时会强制刷新缓冲区
    <6> 我们知道C语言的缓冲区由FILE对象开辟,在内存上,当子进程结束刷新缓冲区时,这一操作也相当于对父子进程共用的数据做修改,所以会触发写时拷贝。
    <7> 因为显示器写入时,其刷新方式为行刷新,所以子进程在创建后与结束时时,C语言的缓冲区为空,而向普通文件写入的刷新方式为全刷新,所以子进程继承了父进程C语言缓冲区中的内容,并进行了写时拷贝与刷新。
  1. 补充: printf与scanf系列函数,格式化输入输出的内核
    <1> 键盘与显示器是两个字符设备,即存储于它们中的数据形式都是字符,显示器想要打印数据就必须以字符的形式进行打印
    <2> 可是,很多时候我们想要读取与写入的数据并不是字符类型,所以,我们进行写入读取时都必须要指定数据类型与格式,这样才能够正确的对显示器与键盘进行数据的读写操作。

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

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

相关文章

【笔记】Telephony SIM SPN及运营商名称显示数据来源介绍

来源介绍 网络名称显示 来源及优先级&#xff08;高到低&#xff09; SourceCommentEnhanced Operator Name String(Eons) 名称信息存放&#xff1a; EF_PNN(PLMN Network Name, fid: 6FC5) &#xff1a;LAC和EF_PNN中的Record Identifier EF_OPL(Operator PLMN List, fid: 6FC…

RBA认证是什么?RBA认证的流程是怎么样的

RBA认证&#xff0c;即“责任商业联盟”认证&#xff0c;英文全称是Responsible Business Alliance。这是一个为电子行业或以电子为主要组成部分的行业及其供应链制定的社会责任审核标准。该标准旨在确保工作环境的安全、工人受到尊重并富有尊严、商业营运合乎环保性质并遵守道…

【AI】如何让局域网PC能够访问langchain框架的AI服务

【背景】 在单位内部成功运行了langchain服务&#xff0c;但是发现本地可以用默认8000端口访问&#xff0c;但是局域网内其它机器却无法访问服务页面。 【分析】 首先查看项目文件夹中的server.py。由于这个server.py的存在&#xff0c;我一开始以为langchain整套框架的服务…

哪些因素影响了PCB电路板切割精度?

PCB电路板切割是电子制造过程中一个至关重要的环节&#xff0c;其精度对后续工序的质量和效率具有决定性影响。因此&#xff0c;了解影响PCB电路板切割精度的原因&#xff0c;对于提高电子产品的质量和生产效率具有重要意义。 1. PCB分板机稳定性 PCB分板机的性能直接影响到切…

中国AIGC最值得关注企业产品榜单揭晓!首份应用全景图谱发布

组委会 发自 凹非寺 量子位 | 公众号 QbitAI “你好&#xff0c;新应用&#xff01;” 站在大模型落地元年&#xff0c;是时候喊出这句话了。 从软件APP、智能终端乃至具身智能等等&#xff0c;AIGC开始席卷一切。 大模型玩家、互联网巨头、终端厂商、垂直场景玩家纷纷入场…

web测试基础知识

目录 web系统的基础 web概念(worldwideweb) 网络结构 发展 架构 B/S C/S P2P 工作原理 静态页面 动态页面 web客户端技术 浏览器的核心--渲染引擎 web服务器端技术 web服务器 应用服务器 集群环境 数据库 案例-URL 协议类型 主机名 端口 IP地址 分类 …

Ubuntu 安装 Harbor

一、安装 docker 原文参考传送门 1st 卸载系统自带的 docker 应用 for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done 2nd 设置Docker 的apt源 # Add Dockers official GPG key: sudo…

翻译《The Old New Thing》 - Some reasons not to do anything scary in your DllMain

Some reasons not to do anything scary in your DllMain - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20040127-00/?p40873 Raymond Chen 2004年01月27日 简介 这篇文章讨论了为什么不应该在DLL的DllMain函数中执行复杂的操作 正文 众所…

SAP DMS创建文档根目录操作简介

前面我们已经对DMS的后台进行了系统的配置,本文开始我们对DMS的前台操作进行说明 1、CV01N创建文档 注意:EDIPUBLICROOTFOLDER为根目录的凭证号,不允许更改。 输入好后回车。进入下图所示: 点击文档浏览器,进入下一屏如下图: 注意:点击创建新的私人文件夹按创建是创…

使用CSS3 + Vue3 + js-tool-big-box工具,实现炫酷五一倒计时动效

时间过得真是飞速&#xff0c;很快又要到一年一度的五一劳动节啦&#xff0c;今年五天假&#xff0c;做好准备了吗&#xff1f;今天我们用CSS3 Vue3 一个前端工具库 js-tool-big-box来实现一个炫酷的五一倒计时动效吧。 目录 1 先制作一个CSS3样式 2 Vue3功能提前准备 3…

基于DEAP数据集的四种机器学习方法的情绪分类

在机器学习领域&#xff0c;KNN&#xff08;K-Nearest Neighbors&#xff09;、SVM&#xff08;Support Vector Machine&#xff09;、决策树&#xff08;Decision Tree&#xff09;和随机森林&#xff08;Random Forest&#xff09;是常见且广泛应用的算法。 介绍 1. KNN&am…

windows本地提权--令牌窃取烂土豆UAC

免责声明:本文仅做技术交流与学习,请知法守法,不要乱搞破坏等等... 目录 一.令牌窃取 操作: 1-生成-->上传后门后,让msf上线 2-执行命令 二.烂土豆(MS16-075) 操作: 1-先让MSF上线 2-上传烂土豆 3-执行命令 三.UAC(用户账户控制) 1-MSF模块提权 2-UACME 项目(yy…

Kafak详解(1)

简介 消息队列 为什么要有消息队列 图-1 消息队列的使用 消息队列 1)消息Message&#xff1a;网络中的两台计算机或者两个通讯设备之间传递的数据。例如说&#xff1a;文本、音乐、视频等内容。 2)队列Queue&#xff1a;一种特殊的线性表(数据元素首尾相接)&#xff0c;特…

应对电网挑战!lonQ与橡树岭国家实验室利用量子技术改善关键基础设施

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨浪味仙 排版丨沛贤 深度好文&#xff1a;1800字丨6分钟阅读 摘要&#xff1a;美国电网正在面临需求增加和能源扩散的挑战&#xff0c;对能够应对优化和安全挑战的创新解决方案有着迫切需求…

黑马鸿蒙学习5:LIST容器

LIST容器&#xff0c;其实就是如果FOREACH容器展示不全的话&#xff0c;会自动有滚动条了。要注意的是&#xff0c;LIST中必须有固定的listitem这个项&#xff0c;而且列表里面只能包含一个根组件。 必须把ROW容器放到listitem中&#xff0c;如下&#xff1a;

node+vue3的websocket前后端消息推送

nodevue3的websocket前后端消息推送 前期写web项目时&#xff0c;前端获取数据的方式一般是向后端发起数据请求&#xff0c;然后后端向前端发送数据&#xff0c;然后对数据进行渲染&#xff0c;这是最常规的一种数据通讯方式&#xff0c;适用于绝大部分前后端分离的项目 实际…

云原生的基石:containerd引领未来容器发展趋势

文章目录 一、Containerd简介&#xff1a;容器技术的心脏二、Containerd核心原理解析三、Containerd与Docker的关系四、Containerd在云原生应用部署中的作用五、Containerd的扩展性和插件机制六、Containerd的安全特性七、Containerd的性能优化八、Containerd的社区和生态系统九…

阿里云mysql8.0 this is incompatible withsql mode=only full group by

阿里云RDS中mysql5.6升级为8.0后&#xff0c;出现如下问题&#xff1a; ### Error querying database. Cause:java.sql.SQLSyntaxErrorException: Expression #1 of SELECT listis not in GROUP BY clause and contains nonaggregatedcolumn temp.product_id which is not fun…

SMT工艺上出现焊锡球,将有什么影响?

在表面贴装技术&#xff08;SMT&#xff09;加工过程中&#xff0c;可能会出现焊锡球形成的问题&#xff0c;焊锡球的存在不仅影响产品的外观质量&#xff0c;还可能导致电路短路&#xff0c;从而影响产品性能和可靠性&#xff0c;所以必须提前了解焊锡球的形成原因&#xff0c…

Python-VBA函数之旅-input函数

目录 一、input函数的常见应用场景&#xff1a; 二、input函数使用注意事项&#xff1a; 三、如何用好input函数&#xff1f; 1、input函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博…