[Linux]文件描述符(万字详解)

news2024/11/27 22:22:32

[Linux]文件描述符

文章目录

  • [Linux]文件描述符
    • 文件系统接口
      • open函数
      • close函数
      • write函数
      • read函数
      • 系统接口与编程语言库函数的关系
    • 文件描述符
      • 文件描述符的概念
      • 文件数据交换的原理
      • 理解“一切皆文件”
      • 进程默认文件描述符
      • 文件描述符和编程语言的关系
    • 重定向
      • 输出重定向
      • 输入重定向
      • 追加重定向
      • 使用指令完成重定向
      • 重定向系统调用
    • C语言文件缓冲区

文件系统接口

在学习文件描述符前,首先要了解一下Linux系统常用的文件系统接口。

open函数

//open函数所在的头文件和函数声明
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
  • open函数有两个接口,三个参数的接口是在两个参数的接口的基础上添加了控制创建文件的权限功能,更适合写文件时使用
  • pathname参数 – 要打开的文件所在的路径
  • flags参数 – 打开文件的方式
  • mode参数 – 如果要创建文件,文件的权限
  • 函数成功返回一个新的文件描述符,函数失败返回-1,错误码被设置。

其中flags参数采用位图结构来接收要操作文件的打开模式,位图结构在这里的作用是只使用一个参数就可以传入多个标志信息,位图结构的具体形式是将flags参数的这样一个32位的整形变量中的每一个比特位都看作为一个个体,每个比特位都代表一个标志信息,位图结构的示意图如下:

image-20230901110937034

假设flags参数的倒数第一比特位表示是否清空文件,如果该比特位为1表示需要清空文件,如果为0则表示不需要清空文件。

为了测试open函数编写如下代码:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  int fd = open(LOG, O_WRONLY);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
  return 0;
}

编译代码运行并查看结果:

image-20230901112138630

由于当前路径下不存在log.txt文件,O_WRONLY打开模式是以读的方式打开文件,因此open函数使用失败,从错误信息中也可以看到失败原因是文件不存在。

再编写如下代码测试open函数:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  int fd = open(LOG, O_WRONLY | O_CREAT);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
  return 0;

编译代码运行并查看结果:

image-20230901112558183

执行程序后,我们能够发现由于文件权限是存在问题的,因此文件名被高亮显式了,由于本次使用的是O_WRONLY | O_CREAT 模式打开 O_CREAT模式是如果文件不存在就创建文件,但是由于没有设置权限,因此文件权限存在问题。

再编写如下代码测试open函数:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  umask(0);
  int fd = open(LOG, O_WRONLY | O_CREAT, 0666);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
    else  printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
  return 0;
}

编译代码运行并查看结果:

image-20230901122558019

三参数的open函数接口第三个接口提供了创建文件是设置文件权限的功能,另外本段代码中使用了umask函数,设置了该进程所使用的umask值,保证所创建的文件权限是想获得的。

//umask函数所在的头文件和函数声明
#include <sys/types.h>
#include <sys/stat.h>

mode_t umask(mode_t mask);

close函数

//close函数所在的头文件和函数声明
#include <unistd.h>

int close(int fd);
  • close函数关闭文件能够避免文件内容出现问题
  • close函数要关闭对应文件要传入使用open函数打开该文件时的返回值(文件描述符)
  • 成功返回0,失败返回-1并且设置错误码

编写如下代码测试close函数:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  umask(0);
  int fd = open(LOG, O_WRONLY | O_CREAT, 0666);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
  else  printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));

  close(fd);
  return 0;
}

编译代码运行并查看结果:

image-20230901123637228

write函数

//write函数所在的头文件和函数声明
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • write函数能够将数据写入相应的文件中
  • fd参数 – 用open函数打开该文件时的返回值(文件描述符)
  • buf参数 – 要写入文件的数据
  • count参数 – 要写入到文件中的数据字节数
  • 成功返回写入的数据字节数,失败返回-1并且设置错误码

编写如下代码测试write函数:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  umask(0);
  int fd = open(LOG, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
  else  printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));

  const char* msg = "hello world\n";
  write(fd, msg, strlen(msg)); 

  close(fd);
  return 0;
}

编译代码运行并查看结果:

image-20230901124130335

说明:

  • O_TRUNC模式是在打开文件时先清空文件
  • 向文件写入数据时不需要将'\0'写入,其作用是在语言上表示字符串的结尾,在文件中不需要。

再编写如下代码测试write函数:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  umask(0);
  int fd = open(LOG, O_WRONLY | O_CREAT | O_APPEND, 0666);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
  else  printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));

  const char* msg = "hello world i love you\n";
  write(fd, msg, strlen(msg));

  close(fd);
  return 0;
}

编译代码运行并查看结果:

image-20230901125840962

说明: O_APPEND模式是采用追加的方式,需要和O_WRONLY模式配合使用才能实现追加写入。

read函数

//read函数所在的头文件和函数声明
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
  • read函数能够读取文件中的数据
  • fd参数 – 要读取的文件的文件描述符
  • buf参数 – 接收文件中数据的字符串变量地址
  • count参数 – buf能接收的最大数据量,单位为字节
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  int fd = open(LOG, O_RDONLY);
  if (fd == -1)
  {
    printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));
    exit(1);
  }
  else  printf("fd: %d, errno: %d, errstring: %s\n", fd, errno, strerror(errno));

  char buffer[256];
  ssize_t n = read(fd, buffer, sizeof(buffer)-1);
  if (n > 0)
  {
    buffer[n] = '\0';
  }
  printf("buffer: %s", buffer);
  close(fd);
  return 0;
}

编译代码运行并查看结果:

image-20230901132135484

说明:

  • O_RDONLY模式是以读取的方式打开文件
  • 用于接收read函数读取到的数据的字符串要在末尾预留一个元素存储'\0'

系统接口与编程语言库函数的关系

由于计算机的体系结构中,操作系统是对上向用户提供服务,向下管理硬件的部分,并且文件的操作是会涉及到硬件的使用,导致编程语言语言库函数中的文件操作一定是对系统接口的封装,无论任何编程语言都是如此,因此无论何种编程语言其文件操作的本质都是相同的。计算机体系结构示意图如下:

image-20230901133244418

文件描述符

文件描述符的概念

在学习文件描述符前要知道,观察Linux操作系统的文件系统接口,能够看出文件操作和文件描述符强相关,open函数的返回值,close函数、write函数、read函数的参数都是文件描述符。

首先,进行文件操作时,操作系统不会将磁盘中的文件加载到内存中,而是在内存中创建一个描述文件的结构(如下图struct file),该结构会管理一个缓冲区,内存和磁盘文件的数据交换都是通过这个缓冲区。示意图如下:

image-20230903133235469

其次,由于文件操作是由进程调用了系统接口完成的,因此进程控制块(如下图struct task_struct)需要记录这些描述文件的结构,因此进程控制块会申请一块创建一个结构(如下图struct files_struct)描述进程操作的文件,然后在进程控制块中使用一个变量(如下图struct files_struct*)记录这个进程操作的文件的地址。示意图如下:

image-20230903134916356

最后,由于一个进程可以操作的文件数量众多,因此描述进程操作的文件的结构(如下图struct files_struct)中,会用一个数组(如下图struct file* fd_array[])记录所有该进程操作的文件的描述结构(如下图struct file)的地址,而这个数组的下标就是文件描述符。示意图如下:

image-20230903134935591

说明: 文件描述符的存在使得进程管理和文件管理处于轻耦合的状态,二者之间只是使用了文件描述结构的指针联系在了一起。

image-20230903142019614

文件数据交换的原理

  • 进程调用系统接口write之后,操作系统会将要传入到磁盘文件的数据拷贝至该文件描述结构中管理的缓冲区,然后操作系统会根据自身的刷新策略,在合适的时候将数据刷新到磁盘文件中。

  • 进程调用系统接口read之后,操作系统会将磁盘文件中的数据拷贝至该文件描述结构中管理的缓冲区,然后将该缓冲区中的内容拷贝至进程指定的位置中。

理解“一切皆文件”

在Linux操作系统中,一切的外设都被看作是文件,因此说“Linux下一切皆文件”。关于“一切皆文件”的理解如下:

首先,操作系统在管理硬件时,并不是直接管理硬件设备的,二者之间要通过驱动程序这一中间软件来完成交互,外设与计算机的交互方式就是数据写入和读取,因此在各个硬件对应的驱动程序中会存在该硬件的读写方法。示意图如下:

image-20230903143346572

虽然驱动程序都设计了对应硬件的读写方法声明,但并不是都有具体实现的,比如键盘只有读取方法,无法向键盘写入。

其次,Linux操作系统会使用描述文件的结构(如下图struct file)来描述每一个外设,并且该结构中会使用函数指针的形式来记录驱动程序所提供的读写方法,然后操作系统要进行外设数据的写入时,只需要将数据写入至文件对应的缓冲区,然后使用函数指针调用对应的函数方法将数据写入写入外设,操作系统读取外设数据时,只需要调用函数指针调用对应的方法将数据写入文件对应的缓冲,然后从缓冲区中读取数据。示意图如下:

image-20230903144604590

由于所有的外设都被统一的使用了描述文件的结构描述,并且进程都是利用缓冲区交换数据,调用对应的读写方法进行读写,其操作方式和文件的操作方式相同,因此从进程的角度看外设和磁盘文件是一样的,因此才说“Linux下一切皆文件”。

进程默认文件描述符

进程在运行时,会默认打开三个文件,分别是标准输入、标准输出、标准错误。为了验证这编写如下代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  int fd = open(LOG, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  printf("fd:%d\n", fd);
  close(fd);
  return 0;
}

编译代码运行并查看结果:

image-20230903151231601

文件描述符代表的是记录进程操作文件的结构的数组的下标,文件描述符的使用规则是从数组起始位置开始,找到第一个没被使用的位置,进程运行时默认打开了标准输入(对应文件描述符为0)、标准输出(对应文件描述符为1)、标准错误(对应文件描述符为2),因此再打开的文件的文件描述符是从3开始。所以能够看到上面的代码打开文件获取的文件描述符为3。

文件描述符和编程语言的关系

在C语言标准库中使用了struct FILE描述文件信息,将标准输入命名为stdin,标准输出命名为stdout,标准错误命名为stderr,由于Linux操作系统的提供的文件操作接口都需要使用文件描述符,因此struct FILE需要包含文件描述符字段。C语言进行进程文件操作和struct FILE强相关,C语言库函数中提供的文件操作函数都会利用struct FILE中记录的文件描述符来调用Linux系统接口来完成。在Linux系统下C语言的struct FILE会有一个变量 _fileno记录文件描述符。为了验证这编写如下代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  printf("stdin:%d\n", stdin->_fileno);
  printf("stdout:%d\n", stdout->_fileno);
  printf("stderr:%d\n", stderr->_fileno);
  FILE* fp = fopen("LOG", "w");
  printf("fp:%d\n", fp->_fileno);
  fclose(fp);
  return 0;
}

编译代码运行并查看结果:

image-20230903154929366

在Linux操作系统中,无论何种编程语言,只要使用文件操作必然需要对文件描述符进行一定的封装来使用,才能完成Linux操作系统下的文件操作。

重定向

输出重定向

输出重定向是将进程原本应该打印到显示器上的数据,输出到文件中。

实现输出重定向的原理: 输出函数是将文件描述符1作为参数调用系统接口函数实现的,修改文件描述符表中1号位置指向的文件,即可完成输出重定向。输出函数的封装中只是使用文件描述符1,无法知晓输出位置的改变。落实到C语言中就是printf是向stdout输出数据,但是stdout也只是封装了文件描述符1,修改文件描述符表中的指向的文件,printf也无法知晓。

为了模式实现输出重定向编写如下代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  int fd = close(1);
  open(LOG, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  printf("hello world\n");
  printf("hello world\n");
  printf("hello world\n");
  close(fd);
  return 0;
}

编译代码运行查看结果:

image-20230903163810294

输入重定向

输入重定向是将进程原本应该从键盘中获取数据,变为从文件中获取数据。

实现输入重定向的原理: 输入函数是将文件描述符0作为参数调用系统接口函数实现的,修改文件描述符表中0号位置指向的文件,即可完成输入重定向。输入函数的封装中只是使用文件描述符0,无法知晓输入位置的改变。落实到C语言中就是scanf是从stdin获取数据,但是stdin也只是封装了文件描述符0,修改文件描述符表中的指向的文件,scanf也无法知晓。

为了模式实现输入重定向编写如下代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  close(0);
  int fd = open(LOG, O_RDONLY);
  int a = 0;
  int b = 0;
  scanf("%d %d", &a, &b);
  printf("%d %d\n", a, b);
  close(fd);
  return 0;
}

编译代码运行查看结果:

image-20230903164454740

追加重定向

追加重定向是将进程原本应该追加打印到显示器上的数据,变为追加打印到文件中。

实现追加重定向的原理: 将输出函数使用的文件描述符1指向改为指定文件,并且在打开文件时使用追加的方式。

为了模式实现追加重定向编写如下代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  close(1);
  int fd = open(LOG, O_WRONLY | O_CREAT | O_APPEND, 0666);
  printf("hello world\n");
  printf("hello world\n");
  printf("hello world\n");
  close(fd);
  return 0;
}

编译代码运行查看结果:

image-20230903174215021

说明: 在实现重定向时也可以选择如下的输入或输出方式:

fscanf(stdin, ...);		//等效于scanf
fprintf(stdout, ...);	//等效于printf

使用指令完成重定向

Linux操作系统中可以使用指令完成重定向,为了验证编写如下代码:

#include <stdio.h>

int main()
{
  printf("hello->printf\n");
  fprintf(stdout, "hello->fprintf stdout\n");

  fprintf(stderr, "hello->fprintf stderr\n");
  return 0;
}

编译代码运行查看结果:

image-20230903175329455

./myfile > log.txt将./myfile的输出重定向到 log.txt文件中,也就是将 log.txt的文件信息写入到该进程的文件描述符1中,2>&1是将该进程的文件描述符1的文件信息写入到文件描述符2中。

重定向系统调用

Linux操作系统中提供了能够重定向的系统调用dup2

//dup2函数所在的头文件和声明
#include <unistd.h>

int dup2(int oldfd, int newfd);
  • dup2函数会将输出到文件描述符newfd的数据改为输出到文件描述符oldfd对应的文件中。
  • dup2函数会将文件描述符oldfd的文件信息写入到文件描述符newfd的文件信息中。

为了验证dup2编写如下代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define LOG "log.txt"

int main()
{
  int fd = open(LOG, O_WRONLY | O_CREAT | O_TRUNC);
  dup2(fd, 1);
  printf("this is printf\n");
  fprintf(stdout, "this is fprintf->stdout\n");
  close(fd);
  return 0;
}

编译代码运行查看结果:

image-20230903182422548

C语言文件缓冲区

在C语言标准库中提供的struct FILE中包含了缓冲区字段,使用C语言库函数中的文件操作向文件写入数据,C语言标准库只会将数据写入到对应文件的struct FILE中的缓冲区,然后结合一定的刷新策略将缓冲区中的内容刷新到Linux操作系统中的文件缓冲区中。示意图如下:image-20230903191243869

缓冲区刷新策略:

  • 无缓冲 – 数据不经过缓冲区直接写入操作系统

  • 行缓冲 – 数据写入缓冲区后遇到'\n',将'\n'及以前的数据写入操作系统

  • 全缓冲 – 缓冲区写满后将数据写入操作系统

  • 显示器采用的刷新策略:行缓冲

  • 普通文件采用的刷新策略:全缓冲

将缓冲区中的数据刷新到操作系统需要使用系统调用,而系统调用的使用要花费大量时间,因此采用缓冲区刷新策略,可以提高效率。

为了验证C语言struct FILE中的缓冲区编写如下代码:

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

#define LOG "log.txt"

int main()
{
  fprintf(stdout, "hello fprint->stdout\n");

  const char* msg = "hello write\n";
  write(1, msg, strlen(msg));

  fork();
  return 0;
}

编译代码运行查看结果:

image-20230903193030324

由于不进行重定向时,打印数据的位置是显示器,采用的是行缓冲的策略,因此数据会在创建子进程前被刷新到操作系统,进行重定向后打印数据的位置是普通文件,采用的是全缓冲的策略,但数据不够写满缓冲区,因此数据会在进程解说,也就是创建子进程之后刷新,而无论父子进程哪一个先刷新都会发生写时拷贝,导致最终数据被刷新到操作系统两次。调用系统调用wrire是直接写入操作系统因此不受影响。

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

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

相关文章

RK3568 USB支持接口类型

一.简介 RK356x 总共支持 4 个 USB 外设接口&#xff0c;包括 1 个OTG 接口&#xff0c;1 个 USB 3.0 Host 接口&#xff0c;以及 2 个 USB 2.0 Host 接口。 二.常用接口类型介绍 Type-C 接口类型&#xff1a; Type-A 接口类型&#xff1a; Type-A USB 3.1 接口&#xff1a;…

el-tree组件的锚点链接

el-tree部分&#xff1a; <el-tree:default-expand-all"true":data"anchorList":props"defaultProps"node-click"handleNodeClick"/> 组件内部部分&#xff1a; <div class"header" :id"content obj.id&q…

javaweb入门版学生信息管理系统-增删改查+JSP+Jstl+El

dao public class StudentDao {QueryRunner queryRunner QueryRunnerUtils.getQueryRunner();//查询全部学生信息public List<Student> selectStudent(){String sql "select * from tb_student";List<Student> students null;try {students queryRunn…

机器学习笔记之最优化理论与方法(五)凸优化问题(上)

机器学习笔记之最优化理论与方法——凸优化问题[上] 引言凸优化问题的基本定义凸优化定义&#xff1a;示例 凸优化与非凸优化问题的区分局部最优解即全局最优解凸优化问题的最优性条件几种特殊凸问题的最优性条件无约束凸优化等式约束凸优化非负约束凸优化 引言 本节将介绍凸优…

Swift 技术 视频播放器滚动条(源码)

一直觉得自己写的不是技术&#xff0c;而是情怀&#xff0c;一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的&#xff0c;希望我的这条路能让你们少走弯路&#xff0c;希望我能帮你们抹去知识的蒙尘&#xff0c;希望我能帮你们理清知识的脉络&#xff0…

数学建模--非多项式拟合法的Python实现

目录 1.算法异同区别 2.算法核心步骤 3.算法核心代码 4.算法效果展示 1.算法异同区别 #*************************************************************************************************************# 方法区别探究 1.对于多项式拟合你需要大致知道这些点的分布&#xf…

对Excel表中归类的文件夹进行自动分类

首先把excel表另存为.txt文件&#xff08;注意&#xff1a;刚开始可能是ANSI格式&#xff0c;需要转成UTF-8格式&#xff09;&#xff1b;再新建一个.txt文件&#xff0c;重命名成.bat文件(注意&#xff1a;直接创建的如果是是UTF-8格式&#xff0c;最好转成ANSI格式&#xff0…

WEBGL(5):绘制线

1 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, …

零基础教程:使用yolov8训练自己的目标检测数据集

1.前言 Ultralytics YOLOv8 是一款前沿、最先进&#xff08;SOTA&#xff09;的模型&#xff0c;基于先前 YOLO 版本的成功&#xff0c;引入了新功能和改进&#xff0c;进一步提升性能和灵活性。YOLOv8 设计快速、准确且易于使用&#xff0c;使其成为各种物体检测与跟踪、实例…

1782_Adobe Reader X实现pdf分页保存

全部学习汇总&#xff1a; GitHub - GreyZhang/windows_skills: some skills when using windows system. 看了一本pdf电子书&#xff0c;觉得其中几页很值得分享。如果分享整本书当然是不错的选择&#xff0c;但是分享整本书很可能会导致一个结局——内容太多别人不会去看&…

rz命令无法正常使用?

使用rz命令上传文件时出现如下问题&#xff1a; 这里用的是mobaxterm终端 改用xshell,secureCRT即可正常使用&#xff1a;

Ubutnu允许ssh连接使用root与密码登录

文章目录 1. 修改sshd_config2. 设置root密码3. 重启SSH服务 1. 修改sshd_config 修改/etc/ssh/sshd_config文件&#xff0c;找到 #Authentication&#xff0c;将 PermitRootLogin 参数修改为 yes。如果 PermitRootLogin 参数被注释&#xff0c;请去掉首行的注释符号&#xff…

人大金仓国产数据库在线下载体验测试版本安装方法

在线下载人大金仓数据库体验测试版本方法 下载地址如下&#xff1a; https://www.kingbase.com.cn/rjcxxz/index.htm #下载windows版本地址参考 https://blog.csdn.net/qq_57052445/article/details/130427207https://www.kingbase.com.cn/sqwjxz/index.htm此处需要下载获取…

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书山东师范大学图书馆

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书山东师范大学图书馆

openGauss学习笔记-59 openGauss 数据库管理-相关概念介绍

文章目录 openGauss学习笔记-59 openGauss 数据库管理-相关概念介绍59.1 数据库59.2 表空间59.3 模式59.4 用户和角色59.5 事务管理 openGauss学习笔记-59 openGauss 数据库管理-相关概念介绍 59.1 数据库 数据库用于管理各类数据对象&#xff0c;与其他数据库隔离。创建数据…

1781_通用型归并排序函数的C语言实现

全部学习汇总&#xff1a; GitHub - GreyZhang/c_basic: little bits of c. 近期在学习C语言数据结构&#xff0c;看到了排序。我看得是一本国外的书籍&#xff0c;直接网上寻找到的一个英文版。内容比较简洁&#xff0c;讲解也算是调理清晰。 关于排序算法&#xff0c;书中只…

DT vray(焦散 间接照明 图像照明)

折射属性 焦散 材质覆盖 基于图像的照明 双面材质 间接照明 开启GI 光子映射 边上 Irradiance Maps 渲染平滑几何体

项目文章 |首次发现太平洋亚历山大藻(甲藻)快速生长中H3K4me3修饰

发表单位&#xff1a;中国海洋大学海洋遗传育种教育部重点实验室 发表日期&#xff1a;2022年11月30日 期刊 &#xff1a;Frontiers in Marine Science &#xff08;IF2022: 5.247&#xff09; 2022年11月30日中国海洋大学海洋遗传育种教育部重点实验室在Frontiers in Marin…

java八股文面试[多线程]—— as-if-serial

什么是as-if-serial 我不管你编译器和执行器怎么处理指令&#xff0c;怎样的进行指令重排&#xff0c;我要求的单线程所执行的结果不能受影响&#xff0c;我不管你年轻时候犯了什么错&#xff0c;你在人生的过程是怎样来的&#xff0c;我只管你结果是不是成功的。在计算机中&a…

Linux系统中调试GDB调试方法入门分享

本篇讲解使用GDB调试Linux应用程序&#xff0c;以下以 hellowld.c 为例介绍 GDB 的调试入门&#xff1a; 编写代码 #include <stdio.h>int main(int argc, char **argv) {int i;int result 0;if(1 > argc){printf("Helloworld.\n");}printf("Hello W…