【Linux】文件描述符——万字详解

目录

前言

预备知识 

复习C语言的文件接口

写方式打开文件

追加方式打开文件

读方式打开文件

系统的文件接口

open

close 

write

read

文件描述符

0 & 1 & 2 

理解文件描述符

文件描述符的分配规则

重定向的本质

dup2

理解Linux下一切皆文件

缓冲区

认识缓冲区 

缓冲区的体现


前言

本篇文章内容有点多,但是非常的重要,,希望你可以坚持看下去,看会你将会对Linux下一切皆文件有一个全新的理解。

如果内容有错或者不足,还望你能指出,让我们共同进步

预备知识 

知识点1 

当我们创建了一个空文件时,这个空文件是否会占空间呢?

答案是:当然啦,因为文件 = 内容 + 属性,文件的属性也是数据当然会占空间啦

因此我们对文件的操作无外乎是对文件的内容或者文件的属性做操作。

知识点2

文件会被加载到磁盘中,我们在C语言或者其它语言中通过编写代码并运行来访问文件,那么这本质是谁在访问文件呢?

答:是进程通过C语言或者其它语言给我们提供的文件接口来访问的。

知识点3 

我们的磁盘是属于硬件,我们普通用户是没有权利向硬件中写入的,只有操作系统才有这个权利,而我们也想要向硬件中写入的话必须通过操作系统提供给我们的接口才能向磁盘中写入。

知识点4

显示器也是属于硬件,我们在C语言中使用printf向显示器中打印时,其实和向磁盘中写入是一样的,没有本质的区别。 

知识点5

所有的语言给我们都提供了有文件访问接口,其实在底层实现都封装的是系统调用的接口,那么这些语言为什么要封装其接口呢?

封装的原因是系统调用的接口比较难,为了能让这些接口更好的给用户使用,所以在语言层面上对这些接口进行了封装。并且这些语言为了实现跨平台性,在底层把所用平台提供的文件接口都实现了一遍,通过条件编译的方式将这些代码进行动态裁剪(就跟多态才不多),这样就能实现在不同平台调用的文件访问接口都是一样的。

知识点6

Linux下一切皆文件,在这里先有个感性的认识,站在你写代码的角度,你会认为加载到内存中的就是文件,但站在系统的角度,能够被读取或者能够被写入的设备就叫做文件。

狭义上理解的文件:普通的磁盘文件

广义上理解的文件:几乎所有外设都可被称为文件。

复习C语言的文件接口

文件打开的方式

写方式打开文件

 先来看看下面的代码

#include <stdio.h>int main()
{FILE *fp = fopen("log.txt", "w");if(fp == NULL){perror("fopen");return 1;}fclose(fp);return 0;
}

我们都知道当我们执行这份代码时,如果当前路径下没有log.txt文件,w方式会在当前路径下创建log.txt文件,那么什么叫做当前路径呢?

所以当前路径是指当你的进程运行起来时所处的工作路径

在来看看下面的代码

#include <stdio.h>
#include <string.h>int main()
{FILE *fp = fopen("log.txt", "w");if(fp == NULL){perror("fopen");return 1;}const char *s1 = "hello man\n";fwrite(s1, strlen(s1), 1, fp);fclose(fp);return 0;
}

我们知道字符串的末尾是会加上一个'\0',那么这里的strlen(s1)是否要加1呢?

答案肯定是不要的,因为'\0'结尾是C语言的规定,文件不需要遵守,并且文件中要保存的是有效数据,'\0'不是有效数据。如果你加上1的话就会出现以下乱码的情况。

当我们以w方式写入时,是先清空文件中的内容再写入。

把上个图片中的hello man和乱码清除再写入hello Linux

这个就和输出重定向很像

追加方式打开文件

#include <stdio.h>
#include <string.h>int main()
{FILE *fp = fopen("log.txt", "a");if(fp == NULL){perror("fopen");return 1;}const char *s1 = "hello Linux\n";fwrite(s1, strlen(s1), 1, fp);fclose(fp);return 0;
}

 

读方式打开文件

#include <stdio.h>
#include <string.h>int main(int argc, char *argv[])//命令行参数
{if(argc != 2){printf("argv error");return 1;}FILE *fp = fopen(argv[1], "r");if(fp == NULL){perror("fopen");return 2;}char line[64];while(fgets(line, sizeof(line), fp) != NULL){fprintf(stdout, "%s", line);//向显示器输出}fclose(fp);return 0;
}

这样就实现了和cat一样的功能

在上面的代码中用到了一个stdout,这个stdout为标准输出

在C语言中会默认打开三个标准输入输出流:stdin、stdout、stderr

并且这三个流的类型都是FILE*的(解释在后面)

系统的文件接口

在上面已经说到了C语言标准库中给我们提供的文件操作的函数在底层其实是调用的系统提供的文件接口,那么系统给我们提供了哪些文件接口呢?下面让我们来认识一下这些文件接口

open

打开成功返回的是一个文件描述符,失败则返回-1

参数介绍

pathname:要打开的目标文件

flags:打开文件的方式。提供了多个选项,可传入多个选项共同构成这个参数

下面三个选项必须指定一个且只能指定一个

  • O_RDONLY:只读
  • O_WRONLY:只写
  • O_RDWR:可读可写

上面选项配合其它选项一起使用,如

  • O_APPEND 表示追加方式的写入文件
  • O_CREAT 表示如果指定文件不存在,则创建这个文件
  • O_TRUNC 表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。
  • ……

这些选项还有好多这里就不一一列举了,大家可以通过man进行查看

可以观察到这些选项都是大写,一般这种大写的基本上是宏定义,这里也不例外。

我们通过或(|)运算就可以将这些选项结合在一起使用了,例如:O_WRONLY|O_CREAT

为什么使用或运算就可以将这些选项结合在一起使用了呢?

其实这里是用到了一个位图的思想,看了下面代码想必你应该就会明白了

#include <stdio.h>
#include <string.h>//用不重复的位就可以标识一个状态
#define ONE 0x1 //0000 0001
#define TWO 0x2 //0000 0010
#define THREE 0x4 //0000 0100void print(int flags)
{//&运算:有0则为0,全1才为1if(flags & ONE) printf("I am ONE\n");if(flags & TWO) printf("I am TWO\n");if(flags & THREE) printf("I am THREE\n");
}int main()
{print(ONE);printf("--------------------------------\n");print(TWO);printf("--------------------------------\n");print(THREE);printf("--------------------------------\n");print(ONE | TWO | THREE);//0000 0001 | 0000 0010 | 0000 0100 = 0000 0111printf("--------------------------------\n");print(ONE | TWO);//0000 0001 | 0000 0010 = 0000 0011printf("--------------------------------\n");print(ONE | THREE);//0000 0001 | 0000 0100 = 0000 0101printf("--------------------------------\n");return 0;
}

库中也确实是这样干的

mode:为设置文件访问的权限

红色区域即为文件的权限,新建文件夹的默认权限是0666,但实际看到的权限不是这个值,因为还会受到umask的影响,umask默认是0002

使用

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);if(fd < 0){perror("open");return 1;}printf("open success, fd:%d\n", fd);return 0;
}

close 

关闭一个文件描述符,成功返回0,失败返回-1并且设置对应的错误码

和fclose的用法就差不多

write

返回值为实际写入的有效数据,ssize_t为有符号整形

参数介绍

fd:为文件描述符

buf:为要写入的数据

count:为写入数据的大小

使用演示

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);if(fd < 0){perror("open");return 1;}printf("open success, fd:%d\n", fd);const char *s1 = "hello write\n";write(fd, s1, strlen(s1));close(fd);return 0;
}

 

read

 

返回值的读取到的有效数据 

参数和write一样就不过多介绍了

使用演示

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd = open("log.txt", O_RDONLY);if(fd < 0){perror("open");return 1;}printf("open success, fd:%d\n", fd);char buffer[64];memset(buffer, '\0', sizeof(buffer));read(fd, buffer, sizeof(buffer));printf("%s\n", buffer);close(fd);return 0;
}

这里系统接口可不会给我们在末尾加上\0,所以我们需要手动在末尾加上'\0'。 

文件描述符

0 & 1 & 2 

先来看一下下面的代码 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd1 = open("log1.txt", O_WRONLY|O_CREAT);int fd2 = open("log2.txt", O_WRONLY|O_CREAT);int fd3 = open("log3.txt", O_WRONLY|O_CREAT);int fd4 = open("log4.txt", O_WRONLY|O_CREAT);printf("open success, fd1:%d\n", fd1);printf("open success, fd2:%d\n", fd2);printf("open success, fd3:%d\n", fd3);printf("open success, fd4:%d\n", fd4);close(fd1);close(fd2);close(fd3);close(fd4);return 0;
}

从上面的的代码可以看出fd都是从3开始的,那么前面的0,1,2去哪里了呢

在上面复习C语言文件接口时,提到过C语言中会默认打开三个标准输入输出流:stdin、stdout、stderr,这三个标准的输入输出流对应的就是0,1,2。

不信的话我们可以验证一下

stdout 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{fprintf(stdout, "hello stdout\n");const char *s1 = "hello 1\n";write(1, s1, strlen(s1));return 0;
}

stdin 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{char buf[64];ssize_t s = read(0, buf, sizeof(buf));if(s > 0){buf[s] = '\0';//在读取到的有效数据的末尾添加\0printf("%s\n",buf);}return 0;
}

我们再回到C语言中,我们在使用C语言的文件函数时都见过FILE*,这个FILE*是一个指针,那么这个FILE是什么呢?

FILE其实是一个结构体,是C语言对底层做出的一个封装,里面包含了很多成员其中就有这个fd(文件描述符)。

#include <stdio.h>int main()
{printf("stdin:%d\n", stdin->_fileno);printf("stdout:%d\n", stdout->_fileno);printf("stderr:%d\n", stderr->_fileno);return 0;
}

理解文件描述符

进程要访问文件,必须先要打开文件,并且一个进程可以打开多个文件,那么如果多个进程都打开自己的文件,系统中就会存在大量被打开的文件,面对如此之多的文件,操作系统肯定要管理起来,而管理的本质就是先描述,再组织。所以在操作系统的内部为了管理每一个被打开的文件,会构建一个结构体,这个结构体中包含了一个被打开的文件的所有内容,然后再将这一个个的结构体用双链表组织起来。

当我们调用open时,必须让进程和文件关联起来,才能打开对应文件,那么我们的进程又是如何和文件关联起来的呢?

在每个进程的PCB中都有一个指针*files,指向一张表files_struct,该表中会包含一个指针数组,数组中的每个元素都是一个指向打开文件的指针,这就实现了和文件进行关联。

那么既然是数组就会有下标,并且是从0开始的,所以文件描述符的本质就是该指针数组的下标。所以只要拿着文件描述符,就可找到对应的文件。

文件描述符的分配规则

从上面的演示中我们就知道了0,1,2已经被三个标准输入输出流给占了,所以我们调用open打开文件时文件描述符(后面就简称fd了)只能从3以后开始,那么我们尝试close关闭0或者2看一下会发生什么现象?

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{//close(0);close(2);int fd = open("log.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); close(fd);return 0;
}

所以fd的分配规则是:当前没有被使用的最小的一个下标

重定向的本质

当我们close关闭1又会发生什么现象呢?

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{close(1);int fd = open("log.txt", O_WRONLY|O_CREAT, 0666);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd); printf("fd: %d\n", fd);fflush(stdout);close(fd);return 0;
}

本该往显示器打印的内容结果打印到文件中去了。

这种现象是不是就和输出重定向是一样的了

本质是在操作系统内部更改了fd对应的内容指向

输入重定向

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{close(0);int fd = open("log.txt", O_RDONLY, 0666);if(fd < 0){perror("open");return 1;}printf("fd: %d\n", fd); char buffer[64];fgets(buffer, sizeof buffer, stdin);printf("%s\n", buffer);fflush(stdout);close(fd);return 0;
}

追加重定向

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{close(1);int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND);if(fd < 0){perror("open");return 1;}fprintf(stdout, "hello hjx\n");fflush(stdout);//刷新缓冲区close(fd);return 0;
}

但事实上重定向并不是这样实现的,我们上面的实现只是利用了fd的分配规则,而在操作系统中早就给我们准备了实现重定向的接口。

dup2

 

dup2的使用描述

这里的意思就是将旧的文件描述符所对应的内容拷贝的新的文件描述符中,最后两个文件描述符是和旧的文件描述符保持一致,如果必要时把新的文件描述符关掉。

dup2的使用

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int fd = open("log.txt", O_WRONLY|O_CREAT|O_APPEND, 0666);if(fd < 0){perror("open");return 1;}dup2(fd, 1);fprintf(stdout, "hello dup2\n");close(fd);return 0;
}

理解Linux下一切皆文件

 Linux下一切皆文件时Linux的一个设计哲学,它是体现在操作系统的软件设计层面的。

我们都知道Linux是用C语言写的,那么你知道怎么用C语言来实现面向对象,甚至是运行时多态吗?

在C++或者其它语言中实现面向对象我们都知道是要用类,类中包含了成员属性和成员方法,但是C语言中只有结构体的概念,而结构体中只能包含成员属性,包含不了成员方法,那该怎么办呢?

没事,我们可以用到一个函数指针来实现其效果。

我们知道操作系统再往下就是硬件(比如磁盘、网卡、键盘、显示器等等)了,这些不同的硬件对应的一定是不同的驱动方法(你访问磁盘和访问键盘是不一样的),但是这些硬件都是外设,所以这每一个设备的核心驱动程序都可以是read/write——>I/O,根据冯诺依曼所有的外设无非都是I/O,所以所有的外设都可以有自己的read和write,但是代码实现一定是不一样的。

这种设计方案就叫做虚拟文件系统(VFS)。 

在Linux内核中也确实是这么干的。 

内核源码

struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*dir_notify)(struct file *filp, unsigned long arg);int (*flock) (struct file *, int, struct file_lock *);
};

缓冲区

认识缓冲区 

缓冲区其实是一段内存空间,就跟你寄快递一样,你把快递交给菜鸟,而菜鸟收到你要寄的快递并不是马上就帮你寄过去,而是先在菜鸟店里暂存等要寄的快递达到一定量时,才一起将这些快递寄出去。而这个例子中的菜鸟就起到了一个缓冲区的作用。

缓冲区的刷新策略分为:1、立即刷新    2、行刷新(行缓冲)   3、满刷新(全缓冲)

但也有特殊情况:1、用户强置刷新(fflush)   2、进程退出

为什么要有缓冲区呢?

缓冲区的出现是为了提高整机的效率,提高用户的响应速度。就比如说你寄快递是你自己亲自送到对方手中好,还是交给菜鸟由菜鸟帮你送好呢?

缓冲区的体现

 再来看一下下面的代码

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main()
{//c语言接口printf("I am printf\n");fprintf(stdout, "I am fprintf\n");const char *s = "I am s\n";fputs(s, stdout);//操作系统接口const char *s1 = "I am s1\n";write(1, s1, strlen(s1));fork();return 0;
}

 注意:fork()之前,fork上面的代码已经是执行完了

我们运行一下往显示器上打印

结果是正常的,没有任何问题,那么我们用输出重定向往文件中打印看看会发生什么呢

我们会发现凡是用了C语言接口的都打印了两次这是为什么呢?

解释:一般而言,我们的显示器采用的都是行刷新策略,而我们的磁盘文件采用的是满刷新策略,并且所有的设备都倾向于满刷新策略,因为缓冲区满了才刷新,可以减少I/O操作以及对外设的访问,从而提高效率。而显示器是给用户看的,为了照顾用户又考虑到效率问题所以采用行刷新策略。所以在上面的代码中,我们向显示器中打印,代码中的 \n 就会起作用——直接刷新到显示器上,而当我们向磁盘文件中打印时,磁盘文件采用的是满刷新,所以 \n 就不会起作用,我们的数据是被放在了缓冲区中,而且从上面的结果来看,缓冲区是语言层面给我们提供的不是系统给我们提供的。不要忘了我们执行完fork后是立即退出了(进程退出了),所以缓冲区中的数据要给我们刷新出来,并且fork创建子进程时,会有写时拷贝的发生。

因此综上所述,写时拷贝+缓冲区是我们的C语言数据打印了两次。

在上面解释中所说的缓冲区是用户级缓冲区,其实操作系统也会提供内核级别的缓冲区(不在写时拷贝的范围内),但是这里就不在讨论了,有兴趣的话可以去内核源码中找一找。

C语言提供的缓冲区

在/usr/include/stdio.h中


struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
//缓冲区相关
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno; //封装的文件描述符
#if 0
int _blksize;
#else
int _flags2;
#endif
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
#define __HAVE_COLUMN /* temporary */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

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

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

相关文章

STM32F4 Hal库中IO外部中断(EXIT)的应用

目录 概述 1 中断和事件 1.1 外部中断/事件控制器 (EXTI) 1.2 EXTI主要特性 1.3 中断和事件的差别 1.3.1 中断产生流程 1.3.2 事件产生流程 1.3.3 STM32F4的事件 2 STM32Cube配置工程 2.1 外部中断/事件介绍 2.2 配置参数 2.3 生成Project 3 STM32F4 Hal库中外部中…

在使用电脑时遇过msvcr120.dll文件丢失的情况怎么办,一键修复dll文件丢失

在使用电脑时有没有遇到过msvcr120.dll文件丢失的情况&#xff0c;遇到这样的情况有什么办法可以解决&#xff0c;废话少说&#xff0c;直接上教程&#xff0c;解决msvcr120.dll文件丢失问题。 msvcr120.dll文件丢失修复方法 A. 从官方或其他可信赖的来源下载并安装缺失的 msv…

众筹商城源码 众筹农业平台 农业乘科技富强之路 线上农业众筹 养殖系统 种植系统源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 前端是编译后的&#xff0c;后端PHP&#xff0c;带商城&#xff0c;详情看下图 特点和功能&#xff1a; 用户管理&#xff1a;包括注册、登录、个人信息管理等。 项目创建与展示&…

【C语言进阶篇】offsetof宏的介绍 及其实现

目录 一、offsetof宏的介绍 头文件 &#xff1a; offsetof宏的通用形式&#xff1a; 参数说明&#xff1a; 用法举例&#xff1a; 二、offsetof宏的实现 三、offsetof宏的使用注意事项 个人主页&#xff1a; 倔强的石头的博客 系列专栏 &#xff1a;C语言指南 …

Java中的动态代理

动态代理 什么是代理程序为什么需要代理例子如何创建代理对象 应用场景 什么是代理 程序为什么需要代理 对象如果认为身上干的事太多&#xff0c;可以通过代理来转移部分职责&#xff1b; 对象有什么方法想被代理&#xff0c;代理就一定要有对应的方法 使用接口实现&#xf…

iPerf 3 测试UDP和TCP方法详解

文章目录 前言一、What is iPerf / iPerf3 ?二、功能1. TCP and SCTP2. UDP3. 其他 三、 Iperf的使用1.Iperf的工作模式2. 通用指令3. 服务端特有选项4. 客户端特有选项5. -t -n参数联系 四、Iperf使用实例1. 调整 TCP 连接1. 1TCP 窗口大小调节1. 2 最大传输单元 (MTU)调整 2…

Pyhton Sqlite3手机数据库

代码结果 Code import sqlite3 connsqlite3.connect(test.db) csconn.cursor() create_tb_sqlcreate table if not exists info(id int primary key,name text,age int)cs.execute(create_tb_sql)# cs.execute(insert into info(id,name,age) values(3,"dog_Senior&quo…

华为交换机重置密码

1.进入bootrom 加电后&#xff0c;18S左右&#xff0c;在启动菜单按 CtrlB 进入bootrom&#xff08;3s内&#xff09; 注意&#xff1a;本步骤属于高危操作&#xff0c;一定小心切勿删除系统或修改bootrom密码&#xff01; 输入bootrom密码&#xff0c;按6 看到提示成功后按…

科技云报道:AIGC掀算力需求革命,边缘计算将不再“边缘”

科技云报道原创。 随着以大模型为代表的AIGC时代拉开序幕&#xff0c;算力需求持续爆发&#xff0c;AI与边缘深度融合已是大势所趋&#xff0c;越来越多的企业开始积极布局GenAI。 GenAI技术的商用化部署和应用成为企业竞逐的新阵地&#xff0c;勾勒出大模型从“技术力”转向…

web漏洞合集描述和修复建议

完整Excle文件可移步至知识星球查看下载 星球不定时分享网上各种资料&#xff0c;欢迎大家加入交流。

NX二次开发UF_LAYER(图层相关操作)常用函数

目录 一、概述 二、函数的介绍 2.1 UF_LAYER_ask_category_info &#xff08;查询图层类别信息&#xff09; 2.2 UF_LAYER_ask_category_tag&#xff08;查询图层类别TAG&#xff09; 2.3 UF_LAYER_ask_status&#xff08;查询图层的状态&#xff09; 2.4 UF_LAYER_ask_wo…

docker 报错 error adding seccomp filter rule for syscall clone3

网上有一些说法&#xff0c;例如重新安装docker 但是我自己尝试&#xff0c;用 –security-opt seccompunconfined 就可以&#xff0c;但是需要把这个命令放到紧挨着run的位置&#xff0c;如果放到偏后的位置&#xff0c;可能不起作用。 以下命令是其他网友启动是的命令&…

UG10.如何设置鼠标滚轮操作模型放大缩小方向?

UG10.如何设置鼠标滚轮操作模型放大缩小方向呢&#xff1f;看一下具体操作步骤吧。 首先打开UG10.软件&#xff0c;在主菜单栏选择【文件】下拉菜单&#xff0c;选择【实用工具】。 点击【用户默认设置】。 文章源自四五设计网-https://www.45te.com/45545.html 选中【基本环…

mongodb 安装问题

1. mongodb启动时显示 Illegal instruction (core dumped) mongodb 5.0之后(包括5.0) 开始使用需要使用 AVX 指令集 2.启动时报错 ERROR: child process failed, exited with 1 通过指令 bin/mongod --repair 查看报错信息 根据报错信息进行修改

Ps 滤镜:波浪

Ps菜单&#xff1a;滤镜/扭曲/波浪 Filter/Distort/Wave 波浪 Wave滤镜可以在图像上创建复杂且可控的波浪形变效果。此滤镜提供了丰富的选项&#xff0c;可以精确调整波浪的形状、大小和分布&#xff0c;以实现不同的视觉效果。 “波浪”滤镜通过对图像应用数学波形函数来扭曲图…

自己写的加密案例4——某东方课程头部sign加密

网址&#xff1a;aHR0cHM6Ly9kc2FwaS54ZGYuY24vcHJvZHVjdC92Mi9jbGFzcy9zZWFyY2g 进行抓包分析&#xff0c;发现请求头中由sign加密&#xff0c;简单判断是消息摘要算法。 Sign:d7c68100ca508bb7c8ae284560754303 进行xhr断点&#xff0c;一下子就发现了位置。 s c.sign&…

linux下 Mysql8.0 离线安装

环境&#xff1a;centos7.9 MysqlL8.0.36安装包 链接&#xff1a;https://pan.baidu.com/s/1bKwHr05z8Ye82dT9tntdUA 提取码&#xff1a;3a5z 参考Centos安装MYSQL8(离线可用) 文章目录 1、解压安装2、配置启动2.1 修改配置文件2.2 mysql 启动 3、mysql 测试 1、解压安装 #…

单片机 VS 嵌入式LInux (学习方法)

linux 嵌入式开发岗位需要掌握Linux的主要原因之一是&#xff0c;许多嵌入式系统正在向更复杂、更功能丰富的方向发展&#xff0c;需要更强大的操作系统支持。而Linux作为开源、稳定且灵活的操作系统&#xff0c;已经成为许多嵌入式系统的首选。以下是为什么嵌入式开发岗位通常…

Valentina Studio Pro for Mac:强大的数据库管理工具

Valentina Studio Pro for Mac是一款功能全面、操作高效的数据库管理工具&#xff0c;专为Mac用户设计&#xff0c;旨在帮助用户轻松管理各种类型的数据库。 Valentina Studio Pro for Mac v13.10激活版下载 该软件拥有直观的用户界面&#xff0c;使得数据库管理变得简单直观。…