【Linux】缓冲区

news2025/7/20 13:00:21

目录

  • 🌈前言
  • 🌷1、缓冲区
    • 🍡1.1、缓冲区的理解
    • 🍢1.2、缓冲区在哪里?
    • 🍣1.3、缓冲区的刷新策略
    • 🍣1.4、模拟实现C库函数
  • 🌸2、标准输出流与错误流的区别
    • 🍤2.1、概念
    • 🍥2.3、perror
    • 🍤2.2、标准错误流的意义

🌈前言

本篇文章进行操作系统中缓冲区的学习!!!


🌷1、缓冲区

🍡1.1、缓冲区的理解

什么是缓冲区呢?

  • 缓冲区的本质:就是一段内存

为什么要有缓冲区呢?

  • 解放使用缓冲区的进程的时间(将数据放到缓冲区后,进程继续执行自己的代码)

  • 缓冲区的存在可以集中处理数据刷新,减少I/O的次数,从而达到提高整机的效率!!!

在这里插入图片描述


🍢1.2、缓冲区在哪里?

代码验证:

字符串带‘\n’,会立即刷新到文件中,这是“行刷新”

[lyh_sky@localhost lesson20]$ cat cache.c 
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
	// stdout -> 1号文件描述符
    printf("hello printf!!!\n");
    const char* msg = "hello write!!!\n";
    
    // 1号文件描述符 -> stdout
    write(1, msg, strlen(msg));
	return 0;
}
[lyh_sky@localhost lesson20]$ ./cache 
hello printf!!!
hello write!!!

如果不带回车有什么现象呢?

[lyh_sky@localhost lesson20]$ cat cache.c 
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
	// stdout -> 1号文件描述符 -- 底层封装了write
    printf("hello printf!!!");
    const char* msg = "hello write!!!";
    
    // 1号文件描述符 -> stdout
    write(1, msg, strlen(msg));
    sleep(3);
	return 0;
}
[lyh_sky@localhost lesson20]$ ./cache 
hello write!!!hello printf!!![lyh_sky@localhost lesson20]$ 
  • printf底层封装了write却没有立即刷新的原因,是因为有缓冲区的存在

  • write系统调用是立即刷新缓冲区的

  • 这个缓冲区一定不在write内部!我们曾经所说的缓冲区,不是内核级别的缓冲区!

  • 那么这个缓冲区只能是语言级别的,由C语言提供

FILE是一个结构体,结构体里封装了很多属性,其中必定包含fd、对应语言级别的缓冲区

在这里插入图片描述

  • 既然缓冲区在FILE内部,在C语言中,我们每打开一个文件,都有一个FILE*文件指针返回

  • 意味着,我们没打开一个文件,都有一个fd和属于自己的对应语言级别的缓冲区!!!


🍣1.3、缓冲区的刷新策略

缓冲区的刷新策略分为三种:

  • 无缓冲:数据立即刷新到外设当中 – write()

  • 行缓冲:数据遇到回车换行(‘\n’)后,刷新到外设当中 – 逐行刷新

  • 全缓冲:缓冲区满了后,就刷新到外设当中 – 块设备对应的文件,磁盘文件

注意:全缓冲不一定是要缓冲区满了才会刷新,进程退出和用户强制刷新也会刷新缓冲区!!!

特殊的刷新策略:

  • 进程退出,刷新缓冲区 – 程序退出、exit()

  • 用户强制刷新 – fflush函数

[lyh_sky@localhost lesson20]$ cat cache.c 
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
	// stdout -> 1号文件描述符 -- 底层封装了write
    printf("hello printf!!!");
    const char* msg = "hello write!!!";
    fflush(stdout); // 强制刷新输出缓冲区
    // 1号文件描述符 -> stdout
    write(1, msg, strlen(msg));
    sleep(3);
	return 0;
}
[lyh_sky@localhost lesson20]$ ./cache 
hello printf!!!hello write!!![lyh_sky@localhost lesson20]$ 

如果在刷新之前,关了fd会怎么样呢???

[lyh_sky@localhost lesson20]$ cat cache.c 
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main()
{
    printf("hello printf!!!");            // stdout -> 1
    const char* msg = "hello write!!!";   // 1 -> stdout
    // 刷新之前关闭1号文件描述符
    write(1, msg, strlen(msg));
    close(1);
	return 0;
}

// 只打印了write写入的数据 -- write是立即刷新缓冲区
hello write!!![lyh_sky@localhost lesson20]$ ./cache 

为什么没有回显内容呢?

  • 因为数据一开始被写入到缓冲区中,但是1号文件描述符已经关闭了

  • 当进程退出后,刷新缓冲区,调用write就失败了!!!所以没有回显到显示器当中!


  • printf fwrite 库函数会自带缓冲区,而 write 系统调用没有带缓冲区

  • 另外,我们这里所说的缓冲区,都是用户级缓冲区

  • 其实为了提升整机性能,OS也会提供相关内核级缓冲区

FILE结构体源码

typedef struct _IO_FILE FILE;/usr/include/stdio.h

在/usr/include/libio.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
};

综合测试题:

[lyh_sky@localhost lesson20]$  cat cache.c 
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{

const char* str1 = "hello printf\n";
   const char* str2 = "hello fprintf\n";
   const char* str3 = "hello fputs\n";
   const char* str4 = "hello write\n";
	// C库函数
   printf(str1);
   fprintf(stdout, str2);
   fputs(str3, stdout);
   // 系统调用
   write(1, str4, strlen(str4));
    
   // 创建子进程 -- 执行上面的代码后子进程才开始执行
   fork();
   return 0;
}

[lyh_sky@localhost lesson20]$ ls
cache  cache.c  makefile
[lyh_sky@localhost lesson20]$ ./cache 
hello printf
hello fprintf
hello fputs
hello write

// 重定向到写入到log.txt文件
[lyh_sky@localhost lesson20]$ ./cache > log.txt
[lyh_sky@localhost lesson20]$ ls
cache  cache.c  log.txt  makefile

[lyh_sky@localhost lesson20]$ cat log.txt 
hello write
hello printf
hello fprintf
hello fputs
hello printf
hello fprintf
hello fputs

为什么重定向后除了write系统接口,其他C库函数都回显了二次呢???

理论:

  • 刷新的本质:把缓冲区的数据write到OS内部,清空缓冲区,end置为0

  • 缓冲区是自己的FILE结构体内部维护的,属于父进程内部的数据区域

原因:

注意:如果没有重定向就是“行缓冲”,逐行刷新(遇到\n)

  • 一般C库函数写入文件时是全缓冲的,而写入显示器是行缓冲

  • printf fwrite 库函数会自带缓冲区(之前的很多例子可以说明),当发生重定向到普通文件时,数据的缓冲方式由“行缓冲”变成了“全缓冲”

  • 重定向的本质是全缓冲(里面必定调用了dup2系统接口),数据会暂存到缓冲区中,当执行到fork()时,创建子进程,子进程直接走到retrun

  • 父子进程在退出时,数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据

  • write因为不存在缓冲区,所以不会进行写时拷贝,所以才打印了一次!

  • 进程中某个数据发生改变,就会写时拷贝某个数据


🍣1.4、模拟实现C库函数

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

#define NUM 1024

// 刷新策略标记位
#define NONE_FLUSH 0x0 		// 无缓冲
#define LINE_FLUSH 0x1 		// 行缓冲 
#define FULL_FLUSH 0x2 		// 全缓冲

typedef struct _MyFILE{
    int _fileno; 			// 文件描述符
    char _buffer[NUM]; 		// 缓冲区
    int _end; 			    // 记录缓冲区尾部下标
    int _flags; 			// fflush method
}MyFILE;

MyFILE *my_fopen(const char *filename, const char *method)
{
    assert(filename);
    assert(method);

    int flags = O_RDONLY;

    if(strcmp(method, "r") == 0)
    {
    	flags = O_RDONLY;
    }
    else if(strcmp(method, "r+") == 0)
    {
    	flags = O_RDWR;
    }
    else if(strcmp(method, "w") == 0)
    {
        flags = O_WRONLY | O_CREAT | O_TRUNC;
    }
    else if(strcmp(method, "w+") == 0)
    {
    	flags = O_RDWR | O_CREAT | O_TRUNC;
    }
    else if(strcmp(method, "a") == 0)
    {
        flags = O_WRONLY | O_CREAT | O_APPEND;
    }
    else if(strcmp(method, "a+") == 0)
    {
    	flags = O_RDWR | O_CREAT | O_APPEND;
    }

    int fileno = open(filename, flags, 0666);
    if(fileno < 0)
    {
        return NULL;
    }

    MyFILE *fp = (MyFILE *)malloc(sizeof(MyFILE));
    if(fp == NULL) return fp;
    memset(fp, 0, sizeof(MyFILE));
    fp->_fileno = fileno;
    fp->_flags |= LINE_FLUSH;
    fp->_end = 0;
    return fp;
}

void my_fflush(MyFILE *fp)
{
    assert(fp);

    if(fp->_end > 0)
    {
        write(fp->_fileno, fp->_buffer, fp->_end);
        fp->_end = 0;
        syncfs(fp->_fileno);
    }
}

void my_fwrite(MyFILE *fp, const char *start, int len)
{
    assert(fp);
    assert(start);
    assert(len > 0);

    // abcde123
    // 写入到缓冲区里面
    strncpy(fp->_buffer+fp->_end, start, len); //将数据写入到缓冲区了
    fp->_end += len;

    if(fp->_flags & NONE_FLUSH)
    {}
    else if(fp->_flags & LINE_FLUSH)
    {
        if(fp->_end > 0 && fp->_buffer[fp->_end-1] == '\n')
        {
            //仅仅是写入到内核中
            write(fp->_fileno, fp->_buffer, fp->_end);
            fp->_end = 0;
            syncfs(fp->_fileno);
        }
    }
    else if(fp->_flags & FULL_FLUSH)
    {
    	// 如果写入缓冲区的数据长度等于缓冲区的最大存储数量,则刷新缓冲区
    	if (len == NUM)
    	{
    		write(fp->_fileno, fp->_buffer, fp->_end);
            fp->_end = 0;
            syncfs(fp->_fileno)
    	}
    }
}

void my_fclose(MyFILE *fp)
{
    my_fflush(fp);
    close(fp->_fileno);
    free(fp);
}

int main()
{
    MyFILE *fp = my_fopen("log.txt", "w");
    if(fp == NULL)
    {
        printf("my_fopen error\n");
        return 1;
    }
    //模拟进程退出
    my_fclose(fp);
    return 0;
}

🌸2、标准输出流与错误流的区别

🍤2.1、概念

  • 我们都知道输出流和错误流对应的文件描述符是1和2

  • 1和2对应的外设都是显示器,对其写入就是回显到显示器上

代码验证

#include <iostream>
#include <cstdio>

int main()
{
    // stdout->1
    printf("hello printf->stdout->1\n");
    fprintf(stdout, "hello fprintf->stdout->1\n");
    fputs("hello fputs->stdout->1\n", stdout);
    std::cout << "hello cout->stdout->1" << std::endl;

    std::cout << std::endl;

    // stderr->2
    fprintf(stderr, "hello fprintf->stderr->2\n");
    fputs("hello fputs->stderr->2\n", stderr);
    perror("hello perror");
    std::cerr << "hello cerr->stderr->2" << std::endl;
    return 0;
}

// 输出流和错误流向显示器写入的内容都回显到显示器中了!!!
[lyh_sky@localhost out_errno]$ ./test 
hello printf->stdout->1
hello fprintf->stdout->1
hello fputs->stdout->1
hello cout->stdout->1

hello fprintf->stderr->2
hello fputs->stderr->2
hello perror: Success
hello cerr->stderr->2

我们对该代码进行输出重定向,看看有什么区别!!!

[lyh_sky@localhost out_errno]$ ls
makefile  test  Test.cc
[lyh_sky@localhost out_errno]$ ./test > log.txt
hello fprintf->stderr->2
hello fputs->stderr->2
hello perror: Success
hello cerr->stderr->2

[lyh_sky@localhost out_errno]$ cat log.txt 
hello printf->stdout->1
hello fprintf->stdout->1
hello fputs->stdout->1
hello cout->stdout->1
  • 我们发现只有向1号文件描述符写入的数据被重定向到了文件当中

但是错误流输出的数据被回显到显示器当中,为什么呢?

  • 因为只进行了输出重定向,输出重定向是指把写入stdout的数据重定向到指向的文件中

  • 而stderr是2号fd,它不会写入到stdout,所以会回显到显示器中!!!

在这里插入图片描述

如何将错误流的数据重定向到文件中呢?

  • 使用【./可执行程序 2> 文件名】,即可将错误流的数据重定向到指定文件中
[lyh_sky@localhost out_errno]$ ls
makefile  test  Test.cc

// 这里是将向stdout写入数据重定向到log.txt,向stderr写入数据重定向到errno.tx
[lyh_sky@localhost out_errno]$ ./test > log.txt 2> errno.txt
[lyh_sky@localhost out_errno]$ ls
errno.txt  log.txt  makefile  test  Test.c

[lyh_sky@localhost out_errno]$ cat log.txt 
hello printf->stdout->1
hello fprintf->stdout->1
hello fputs->stdout->1
hello cout->stdout->1

[lyh_sky@localhost out_errno]$ cat errno.txt 
hello fprintf->stderr->2
hello fputs->stderr->2
hello perror: Success
hello cerr->stderr->2

🍥2.3、perror

#include <stdio.h>
void perror(const char *s);
  • 在标准错误输出上生成一条消息,描述在调用系统或库函数时遇到的最后一个错误

  • 第一个参数如果s不为NULL并且*s不是空字节(“\0”),将打印参数字符串s,后跟冒号和空白

模拟实现perror

#include <string.h>
char *strerror(int errnum);
  • 该函数用于获取指向错误消息字符串的指针

  • 可以通过errno获取错误码,然后传递给它,就能获取最近一次的错误信息!!!

[lyh_sky@localhost out_errno]$ cat Test.cc
#include <iostream>
#include <cstdio>
#include <cstring>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

void my_perror(const char *info)
{
    fprintf(stderr, "%s: %s\n", info, strerror(errno));
}

int main()
{
    //fopen: C库函数
    int fd = open("log.txt", O_RDONLY);	//必定失败的 -- 当前进程工作路径下没有该文件
    if(fd < 0)
    {
        //perror("open");
        my_perror("my open");
        return 1;
    }
    return 0}
[lyh_sky@localhost out_errno]$ ls
makefile  test  Test.cc
[lyh_sky@localhost out_errno]$ ./test
my open: No such file or directory
[lyh_sky@localhost out_errno]$ echo $?
1
  • 当系统调用失败时,它通常返回-1,并将变量errno(全局变量)设置为一个描述错误的值(错误码)。(这些值可以在<errno.h>中找到!!!

  • 语言中会有自己一套的错误码,我们也可以使用exit指定进程退出错误码,或者使用return …

  • 如果调用失败的之后没有立即调用perror(),则errno的值也会被保存下来

  • 函数perror()用于将此错误代码转换为一段字符串,回显到显示器


🍤2.2、标准错误流的意义

意义:

  • 可以区分那些是日常程序的输出,哪些是错误

  • 可以帮助我们以后写项目时,快速的差错,这就是“日志”!!!

  • 我们现在写的程序虽然都用不着,但是还得了解一下

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

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

相关文章

微客云升级会员制度

会员制度 会员制度是一种人与人或组织与组织之间进行沟通的媒介&#xff0c;它是由某个组织发起并在该组织的管理运作下&#xff0c;吸引客户自愿加入&#xff0c;目的是定期与会员联系&#xff0c;为他们提供具有较高感知价值的利益包。 Part 1 会员制度 建立长期稳定的客…

Python测试框架之Pytest基础入门

Pytest简介 Pytest is a mature full-featured Python testing tool that helps you write better programs.The pytest framework makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries. 通过官方网站介绍…

Vue子组件传自定义事件给父组件

我们知道组件之间是不能够进行通信的&#xff0c;都是相互独立的&#xff0c;你用不了我的状态和方法&#xff0c;我也用不了你的&#xff0c;那如何实现通信呢&#xff0c;可以间接实现&#xff1b; 实现父组件和子组件的通信&#xff1a; 子组件想用父组件的状态需要父组件…

Apache ShardingSphere(二) 基本使用

文章目录二 ShardingSphere JDBC 基本使用2.1 ShardingSphere JDBC 水平分表2.1.1 案例入门2.1.2 解读配置文件2.1.3 其他测试2.1.4 延伸问题2.2 ShardingSphere JDBC 水平分库2.2.1 案例入门2.2.2 解读配置文件2.1.3 其他测试2.3 ShardingSphere JDBC 广播表2.3.1 基本案例入门…

矩阵链相乘(动态规划)

【问题描述】给定n个矩阵M1,M2...MnM_1,M_2...M_nM1​,M2​...Mn​&#xff0c;他们的维数分别是r1∗c1,r2∗c2...rn∗cnr_1*c_1,r_2*c_2...r_n*c_nr1​∗c1​,r2​∗c2​...rn​∗cn​&#xff0c;要求使用【动态规划】的策略求解矩阵连乘的最优计算代价(总乘法次数最少)。题目…

Docker 学习视频集 bilibili

1.什么是Docker_哔哩哔哩_bilibili 2.Docker的安装_哔哩哔哩_bilibili 3.镜像、容器和仓库_哔哩哔哩_bilibili 4.在容器中部署一个应用_哔哩哔哩_bilibili 5.将容器保存成镜像成片_哔哩哔哩_bilibili 6.使用Dockerfile构建镜像1_哔哩哔哩_bilibili 7.导入导出镜像_哔哩哔…

vscode配合gitee同步云设置

更换开发设备后&#xff0c;新安装的vscode软件&#xff0c;是没有原先的配置的&#xff0c;诸如快捷键&#xff0c;快捷代码段生成、安装的各个插件&#xff0c;插件的配置等都木大了&#xff0c;开发起来会很别扭&#xff0c;网上最多的就是去安装一个叫做Settings Sync的插件…

springcloud五大核心部件

springcloud五大核心部件 一、springcloud介绍 springcloud是微服务的集大成者&#xff0c;将一系列的组件进行了整合。基于springboot构建 &#xff0c;可以快速配置常用模块并构建庞大的分布式系统。 二、具体业务分析 我们举一个例子来进行业务场景分析 假设现在开发一…

Websocket学习

参考&#xff1a;http://www.mydlq.club/article/86/ 这里写目录标题一、WebSocket 简介二、WebSocket 特点三、为什么需要 WebSocket四、WebSocket 连接流程五、WebSocket 使用场景六、使用案例1.提醒客户端有新订单2.客户端交互一、WebSocket 简介 WebSocket 是一种基于 TCP…

为什么越来越多的企业在会议室使用无线流媒体网关?

1&#xff0c;用户已有华为&#xff0c;MAXHUB等投屏功能设备&#xff0c;不需要这个设备了。但是市面上大部分投屏设备的使用存在以下问题&#xff1a; 操作麻烦&#xff0c;我们发射器是直接触摸投屏&#xff0c;安全性低&#xff0c;需要驱动软件。 2&#xff0c;市场上有很…

实现矩阵连乘积(动态规划)

目录 实现矩阵连乘积 题目 问题分析 算法分析 时间复杂度 代码实现 执行结果 动态规划 基本思想 举例 个人主页&#xff1a;天寒雨落的博客_CSDN博客-初学者入门C语言,python,数据库领域博主 &#x1f4ac; 热门专栏&#xff1a;初学者入门C语言_天寒雨落的博客-CSDN…

【SVM分类】基于鸽群算法优化支持向量机SVM实现分类附matlab的代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

arduino 复习题

名词解释 中断 计算机运行过程中&#xff0c;出现某些意外情况需主机干预时&#xff0c;机器能自动停止正在运行的程序并转入处理新情况的程序&#xff0c;处理完毕后又返回原被暂停的程序继续运行 中断服务程序 用于 CPU 处理中断的程序 中断源 引起中断的原因&#xff0c;或…

【JVS低代码平台】如何实现与外部系统/内部代码直接对接?

JVS是开放性的低代码开发平台&#xff0c;为开发团队预留了多种对接的方式。我这里列举集中对接的模式。 用户对接&#xff08;统一登录/单点跳转&#xff09; 在日常的企业需求中&#xff0c;常常有这种情况。企业内部考勤打开都是通过钉钉或者企微的&#xff0c;那么希望我们…

Grasp Detection论文、代码汇总

文章目录2022End-to-end Trainable Deep Neural Network for Robotic Grasp Detection and Semantic Segmentation from RGB2019Antipodal Robotic Grasping using Generative Residual Convolutional Neural Network2022 End-to-end Trainable Deep Neural Network for Robot…

现代PCB生产工艺——加成法、减成法与半加成法

继续为朋友们分享关于PCB生产工艺的知识。 现代PCB生产工艺&#xff0c;目前主要分为&#xff1a;加成法、减成法与半加成法。 其具体定义如下&#xff1a; 加成法&#xff1a; 通过网印或曝光形成图形&#xff0c;经钻孔、沉铜、转移层压等工艺加工&#xff0c;直接将导电图形…

Pycharm开发环境下创建python运行的虚拟环境(自动执行安装依赖包)

问题&#xff1a;基于Django开发的后台程序涉及到很多依赖的开发包&#xff0c;将该项目迁移到其它电脑环境下运行需要搭建环境&#xff0c;由于项目中有requirement.txt&#xff0c;该文件内包含了运行该项目所需的依赖&#xff1b;最简便的方式是执行命令自动安装requirement…

postgresql11 主从配置详解

以下内容是针对pgsql11来做的。请看好版本再去考虑是否往下看 准备两台服务器&#xff0c;地址如下&#xff1a; 主&#xff1a;192.168.0.1pgsql11从:192.168.0.2pgsql11一、主库配置 1、创建具有复制权限的用户replica 密码为000000 CREATE ROLE replica login replicat…

Docker——数据卷命令

目录 一、数据卷 1.1 便于修改 1.2 数据共享 1.3 安全问题 1.4 数据卷的基本语法 二、 创建数据卷&#xff0c;并查看数据卷在宿主机的目录位置 2.1 创建数据卷 2.2 查看所有数据卷 2.3 查看数据卷详细信息卷 2.4 删除数据卷 三、挂载数据卷 3.1 创建容器并挂载数据卷…

智慧国土解决方案-最新全套文件

智慧国土解决方案-最新全套文件一、建设背景二、建设思路1、紧盯三大领域2、划分三个阶段3、面向三个维度三、建设方案轻应用微服务大平台应用设计四、获取 - 智慧国土全套最新解决方案合集一、建设背景 2019年5月9日&#xff0c;印发《关于建立国土空间规划体系并监督实施的若…