Linux知识点 -- 进程间通信(二)

Linux知识点 – 进程间通信(二)

文章目录

  • Linux知识点 -- 进程间通信(二)
  • 一、System V共享内存
    • 1.原理
    • 2.申请共享内存
    • 3.System V共享内存的使用
    • 4.为共享内存添加访问控制
  • 二、信号量(概念理解)
    • 1.概念
    • 2.信号量


一、System V共享内存

1.原理

在这里插入图片描述
先在内存中申请空间,然后将这段空间映射到不同进程的地址空间中,这就叫做共享内存;
一般都是映射在进程的堆栈之间的共享区;
共享内存不属于任何一个进程,它属于操作系统;
操作系统对共享内存的管理,是先描述再组织,先通过内核数据结构描述共享内存的属性信息,再将它们组织起来;
共享内存 = 共享内存块 + 对应的共享内存的内核数据结构;
共享区属于用户空间,不用经过系统调用,直接可以访问;
双方进程如果要通信,直接进行内存级的读写即可;
之前的管道是一种文件。是OS中的一种数据结构,所以用户无权直接访问,需要进行系统调用;

2.申请共享内存

在这里插入图片描述
shmget接口能够申请共享内存;

  • 参数:
    key:通信双方的进程,通过key值来保证是通信的双方来创建的共享内存,相当于一个验证值,需要在系统内是唯一的,通信双方使用同一个key;
    size:内存大小,一般是页(4byte)的整数倍;
    shmflag:有两个选项:IPC_CREAT和IPC_EXCL;
    IPC_CREAT能单独出现,代表如果共享内存已存在,则获取之;如果不存在,就创建之,并返回;
    IPC_EXCL必须和IPC_CREAT组合使用,代表如果共享内存不存在,就创建之,并返回;如果已存在,出错并返回;
    0就代表IPC_CREAT;

    返回值:成功会返回共享内存id,失败返回-1;

ftok函数:生成唯一的key
在这里插入图片描述

  • 参数:
    ==pathname:==文件路径,一定要保证用户有权限;
    ==id:==项目id,随便给,一般是0 - 255;
    返回值:成功,返回key值;失败,返回-1;
    ftok会拿路径文件的inode,和id形成一个唯一的key,生成结果是有可能重复的;

3.System V共享内存的使用

  • Makefile:
.PHONY:all
all:shmClient shmServershmServer:shmServer.ccg++ -o $@ $^ -std=c++11 
shmClient:shmClient.ccg++ -o $@ $^ -std=c++11 .PHONY:clean
claen:rm -f shmServer shmClient
  • Log.hpp
#ifndef _LOG_H_
#define _LOG_H_#include<iostream>
#include<ctime>#define DeBug   0
#define Notice  1
#define Waring  2
#define Error   3const std::string msg[] = {"DeBug","Notice","Waring","Error"
};std::ostream &Log(std::string message, int level)
{std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;return std::cout;
}
#endif
  • comm.hpp
#ifndef _COMM_H_
#define _COMM_H_#include<iostream>
#include<cstdio>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cassert>
#include "Log.hpp"using namespace std;#define PATH_NAME "/usr/lmx" //路径,一定保证有权限
#define PROJ_ID 0X66   
#define SHM_SIZE 4096 //共享内存大小,最好是页(4byte)的整数倍#endif
  • shmServer.cc
    #include “comm.hpp”

string TransToHex(key_t k)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), “0x%x”, k);
return buffer;
}

int main()
{
// 1.创建公共的key值
key_t key = ftok(PATH_NAME, PROJ_ID);
if (key == -1)
{
perror(“ftok”);
exit(1);
}

Log("creat key done", DeBug) << "server key : " << TransToHex(key) << endl;// 2.创建共享内存 -- 建议创建一个全新的共享内存 -- 通信的发起者
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);
if (shmid == -1)
{perror("shmget");exit(2);
}
Log("shm creat done", DeBug) << "shmid : " << shmid << endl;//3.将指定的共享内存,挂接到自己的地址空间
char* shmaddr = (char*)shmat(shmid, nullptr, 0);
Log("attach shm done", DeBug) << "shmid : " << shmid << endl;//这里就是通信逻辑了
//将共享内存看作一个大字符串
//shmaddr就是这个字符串的起始地址
for(;;)
{printf("%s\n", shmaddr);//不断打印这个字符串的内容if(strcmp(shmaddr, "quit") == 0){break;}sleep(1);
}//4.将指定的共享内存,从自己的地址空间中去关联
int n = shmdt(shmaddr);
if(n == -1)
{perror("shmdt");exit(3);
}
Log("detach shm done", DeBug) << "shmid : " << shmid << endl;//5.删除共享内存,IPC_RMID即便是有进程和当下的shm挂接,依旧删除共享内存
n = shmctl(shmid, IPC_RMID, nullptr);
if(n == -1)
{perror("shmctl");exit(4);
}
Log("delete shm done", DeBug) << "shmid : " << shmid << endl;return 0;

}


注意:
(1)
在这里插入图片描述
要保证创建出唯一的key;*
(2)
在这里插入图片描述
创建全新的共享内存,0666代表共享内存的权限;
共享内存的大小最好是页的整数倍,否则会造成空间浪费,多开空间,但是没有权限访问;
在这里插入图片描述
第二次创建的时候,提示共享内存已存在;
在这里插入图片描述
(3)ipcs -m:查看共享内存信息;
在这里插入图片描述
ipcrm -m shmid:删除共享内存(不能用key删除)
共享内存的生命周期随内核;
与文件不一样,文件的生命周期,如果进程退出,没有其他进程再关联这个文件,那么就会被回收;

在这里插入图片描述
在这里插入图片描述
perms属性就是共享内存的权限,

(4)因此,当进程结束后,共享内存还存在,我们继续要删除它,使用系统接口:
shmctl:删除共享内存
在这里插入图片描述
在这里插入图片描述
(5)nattch属性是挂接的共享内存个数,共享内存创建好之后,需要挂接在自己的进程地址空间;
shmat:挂接共享内存
在这里插入图片描述
参数:
shmid:共享内存id
shmaddr:挂接虚拟地址,直接设为0,让os挂接
shmflg:挂接方式
返回值:成功返回共享内存addr虚拟地址,失败返回-1

使用:
将返回值作为共享内存的起始地址;
在这里插入图片描述
shmdt:去关联
在这里插入图片描述
参数:
shmaddr:共享内存地址
返回值:成功返回0,失败返回-1

  • shmClient.cc
#include "comm.hpp"int main()
{// 客户端也获取keykey_t key = ftok(PATH_NAME, PROJ_ID);if (key < 0){Log("creat key failed", Error) << "client key : " << key << endl;exit(1);}Log("creat key done", DeBug) << "client key : " << key << endl;// 获取共享内存int shmid = shmget(key, SHM_SIZE, 0);if (shmid == -1){Log("creat shm failed", Error) << "client key : " << key << endl;exit(2);}Log("creat shm done", DeBug) << "client key : " << key << endl;// 挂接共享内存char *shmaddr = (char *)shmat(shmid, nullptr, 0);if (shmaddr == nullptr){Log("attach shm failed", Error) << "client key : " << key << endl;}Log("attach shm done", DeBug) << "client key : " << key << endl;// 使用//client将共享内存看作一个char类型的buffer//客户端从键盘读取消息,直接读到共享内存中while (true){ssize_t s = read(0, shmaddr, SHM_SIZE - 1);if(s > 0){shmaddr[s - 1] = 0;if(strcmp(shmaddr, "quit") == 0)//读到quit,客户端退出{break;}}}// char a = 'a';// for(; a <= 'z'; a++)// {//     //每一次都向shmaddr(共享内存的起始地址)写入//     snprintf(shmaddr, SHM_SIZE - 1, //             "hello server, 我是其他进程,我的pid: %d, inc: %c\n", //             getpid(), a);//     sleep(2);// }// 去关联int n = shmdt(shmaddr);if (n == -1){perror("shmdt");exit(3);}Log("detach shm done", DeBug) << "client key : " << key << endl;// client不需要删除shmreturn 0;
}

注意:
(1)共享内存的使用,直接将共享内存看作一个char类型的buffer,直接向里面写入数据
在这里插入图片描述
从stdin中键盘读取消息,直接读取到shmaddr这个地址,即共享内存的起始地址;

运行结果:
服务端:
在这里插入图片描述
客户端:
在这里插入图片描述

  • 注:
    (1)只要是通信双方使用shm,一方直接向共享内存中写入数据,另一方就可以立马看到对方写入的数据;共享内存是所有进程间通信中最快的,不需要过多的拷贝;
    (2)管道通信中,一次通信需要多次拷贝,用户从键盘输入数据到缓冲区是一次拷贝,从缓冲区向管道文件写入数据又是一次拷贝,从管道文件向缓冲区读取数据是一次拷贝,从缓冲区将数据打印又是一次拷贝;

    在这里插入图片描述

(3)共享内存只需要两次拷贝,从键盘输入的数据直接写入shm,这是一次拷贝,直接将shm的数据打印出来,这是第二次拷贝;
在这里插入图片描述

4.为共享内存添加访问控制

从上面的结果可以看出,即便是客户端还没有挂接共享内存,服务端就已经开始不停读取数据了,这就表明共享内存是不带访问控制的,会带来一定的并发问题;
然而,管道是自带访问控制的,我们可以利用管道通信来为共享内存添加访问控制;
comm.hpp

#ifndef _COMM_H_
#define _COMM_H_#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cassert>
#include <cstring>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"using namespace std;#define PATH_NAME "/home/lmx" // 路径,一定保证有权限
#define PROJ_ID 0X66
#define SHM_SIZE 4096 // 共享内存大小,最好是页(4byte)的整数倍#define FIFO_NAME "./fifo"class Init
{
public:Init(){umask(0);int n = mkfifo(FIFO_NAME, 0666);assert(n == 0);(void)n;Log("creat fifo succsee", Notice) << "\n";}~Init(){unlink(FIFO_NAME);Log("remove fifo succsee", Notice) << "\n";}
};#define READ O_RDONLY
#define WRITE O_WRONLYint OpenFIFO(std::string pathname, int flags)
{int fd = open(pathname.c_str(), flags);assert(fd >= 0);return fd;
}void Wait(int fd)
{Log("waiting...", Notice) << "\n";uint32_t temp = 0;ssize_t s = read(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;
}void Signal(int fd)
{uint32_t temp = 1;ssize_t s = write(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;Log("aweaking...", Notice) << "\n";
}void CloseFIFO(int fd)
{close(fd);
}#endif

注:
(1)创建了一个类,类的构造函数有创建管道文件,一旦类实例化出对象,调用构造函数,就能够创建一个管道文件,后面就是对管道文件的读写控制了;
在这里插入图片描述
shmServer.cc

#include "comm.hpp"string TransToHex(key_t k)
{char buffer[32];snprintf(buffer, sizeof(buffer), "0x%x", k);return buffer;
}int main()
{Init init;// 对应的程序在加载的时候,会自动构建全局变量,就要调用该类构造函数 -- 创建管道文件// 程序退出的时候,全局变量会被析构,会自动删除管道文件// 1.创建公共的key值key_t key = ftok(PATH_NAME, PROJ_ID);if (key == -1){perror("ftok");exit(1);}Log("creat key done", DeBug) << "server key : " << TransToHex(key) << endl;// 2.创建共享内存 -- 建议创建一个全新的共享内存 -- 通信的发起者int shmid = shmget(key, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);if (shmid == -1){perror("shmget");exit(2);}Log("shm creat done", DeBug) << "shmid : " << shmid << endl;// 3.将指定的共享内存,挂接到自己的地址空间char *shmaddr = (char *)shmat(shmid, nullptr, 0);Log("attach shm done", DeBug) << "shmid : " << shmid << endl;// 这里就是通信逻辑了// 将共享内存看作一个大字符串// shmaddr就是这个字符串的起始地址//使用管道进行访问控制int fd = OpenFIFO(FIFO_NAME, READ);for (;;){Wait(fd);//等待客户端响应,//使用管道文件的访问控制,如果客户端没有向管道内写入数据,那么该进程会一直阻塞printf("%s\n", shmaddr); // 不断打印这个字符串的内容if (strcmp(shmaddr, "quit") == 0){break;}sleep(1);}CloseFIFO(fd);// 4.将指定的共享内存,从自己的地址空间中去关联int n = shmdt(shmaddr);if (n == -1){perror("shmdt");exit(3);}Log("detach shm done", DeBug) << "shmid : " << shmid << endl;// 5.删除共享内存,IPC_RMID即便是有进程和当下的shm挂接,依旧删除共享内存n = shmctl(shmid, IPC_RMID, nullptr);if (n == -1){perror("shmctl");exit(4);}Log("delete shm done", DeBug) << "shmid : " << shmid << endl;return 0;
}

注:
(1)在服务端先创建一个管道文件
在这里插入图片描述
(2)在读取共享内存中的数据前,先读取管道数据,看客户端是否响应;
在这里插入图片描述
shmClient.cc

#include "comm.hpp"int main()
{// 客户端也获取keykey_t key = ftok(PATH_NAME, PROJ_ID);if (key < 0){Log("creat key failed", Error) << "client key : " << key << endl;exit(1);}Log("creat key done", DeBug) << "client key : " << key << endl;// 获取共享内存int shmid = shmget(key, SHM_SIZE, 0);if (shmid == -1){Log("creat shm failed", Error) << "client key : " << key << endl;exit(2);}Log("creat shm done", DeBug) << "client key : " << key << endl;// 挂接共享内存char *shmaddr = (char *)shmat(shmid, nullptr, 0);if (shmaddr == nullptr){Log("attach shm failed", Error) << "client key : " << key << endl;}Log("attach shm done", DeBug) << "client key : " << key << endl;// 使用//client将共享内存看作一个char类型的buffer//客户端从键盘读取消息,直接读到共享内存中//使用管道进行访问控制int fd = OpenFIFO(FIFO_NAME, WRITE);while (true){ssize_t s = read(0, shmaddr, SHM_SIZE - 1);if(s > 0){shmaddr[s - 1] = 0;Signal(fd);//向管道写入数据if(strcmp(shmaddr, "quit") == 0)//读到quit,客户端退出{break;}}}CloseFIFO(fd);// 去关联int n = shmdt(shmaddr);if (n == -1){perror("shmdt");exit(3);}Log("detach shm done", DeBug) << "client key : " << key << endl;// client不需要删除shmreturn 0;
}

注:
(1)在向共享内存写入数据前,先向管道写入信号,表明客户端准备写入数据,唤醒服务端:
在这里插入图片描述

运行结果:
当运行服务端,但是客户端未响应时,服务端会等待客户端响应,进程阻塞;
在这里插入图片描述
当客户端响应时,服务端会被唤醒,读取共享内存中的数据:
在这里插入图片描述
退出:
在这里插入图片描述

二、信号量(概念理解)

1.概念

  • 基于对共享内存的理解:
    为了让进程间通信,让不同的进程之间,看到同一份资源,我们之前讲的所有的进程间通信都是基于这种方式;
    而让不同的进程看到同一份资源,比如共享内存,也带来了一些时序问题,会造成数据的不一致

  • 概念
    (1)临界资源:多个进程(执行流)看到的公共的一份资源;
    (2)临界区:自己的进程,访问临界资源的代码;
    (3)互斥:为了更好的进行临界区的维护,可以让多执行流在任何时刻,都只能有一个进程进入临界区;
    (4)原子性:要么不做,要么做完,没有中间状态;

2.信号量

我们平常看电影前,会先买票,电影院中的座位就相当于资源,当你买了票,这个座位就真正属于你,买票的本质就是对座位的预定机制;
对于进程来说,访问临界资源中的一部分,不能让进程直接去使用临界资源,需要先申请信号量
信号量的本质是一个计数器

  • 申请信号量:
    (1)申请信号量的本质,就是让信号量技术器 - -;
    (2)申请信号量成功,临界资源内部,一定给进程预留了需要的资源,申请信号量的本质就是对临界资源的一种预定机制;

  • 释放信号量:
    释放信号量就是将计数器++;

如果将信号量计数器设为全局变量(整数n,存放在共享内存),让多个进程看到同一个全局变量,大家都能够进行信号量的申请,这样是不行的;
因为CPU在执行n++这个指令的时候,其实执行了三条语句:
(1)将内存中的数据加载到CPU内的寄存器(读指令);
(2)n–(执行指令);
(3)将CPU修改完毕的值再写入内存(写指令);

而执行流在执行的时候,在任何时刻都是能被切换的;
例如:
如果信号量刚开始是5,client在申请信号量的时候,第一步就被切换了,寄存器里的数据保存为上下文数据,
由server申请信号量,如果server将信号量减到2了,此时server被切换,client回来
client回来的时候就会将上下文数据恢复,将信号量恢复为5,再申请信号量,这时信号量就变为了4;

寄存器只有一套,被所有执行流共享,但是寄存器内的数据,属于每一个执行流,属于该执行流的上下文数据;
这样设计,会导致信号量是不安全的;
因此,申请和释放信号量这两个操作,必须是原子的
在这里插入图片描述

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

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

相关文章

OpenCV之信用卡识别实战

文章目录 代码视频讲解模板匹配文件主程序(ocr_template_match.py)myutils.py 代码 链接: https://pan.baidu.com/s/1KjdiqkyYGfHk97wwgF-j3g?pwdhhkf 提取码: hhkf 视频讲解 链接: https://pan.baidu.com/s/1PZ6w5NcSOuKusBTNa3Ng2g?pwd79wr 提取码: 79wr 模板匹配文件 …

Ubuntu开机自启服务systemd.service配置教程(Ubuntu服务)(Linux服务)upstart

文章目录 为什么要将程序配置成服务&#xff1f;1. 自动启动2. 后台运行3. 定时重启4. 简化管理5. 整合系统 版本支持1. Ubuntu 14.04及更早版本&#xff1a;使用upstart作为默认的init系统/etc/rc.local旧版本新版本 2. Ubuntu 15.04到16.04版本&#xff1a;默认使用systemd作…

【敏捷开发】测试驱动开发(TDD)

测试驱动开发&#xff08;Test-Driven Development&#xff0c;简称TDD&#xff09;是敏捷开发模式中的一项核心实践和技术&#xff0c;也是一种设计方法论。TDD有别于以往的“先编码&#xff0c;后测试”的开发模式&#xff0c;要求在设计与编码之前&#xff0c;先编写测试脚本…

1310. 数三角形

题目链接&#xff1a;https://www.acwing.com/problem/content/1312/ 首先不考虑三点共线的情况一共有 种&#xff0c;现在来计算三点共线的情况 1.三点在一条直线上 2.三点在一条竖线上 3.三点在一条斜线上&#xff0c;正反斜线对称&#xff0c;仅需考虑一边的情况 如果…

14-5_Qt 5.9 C++开发指南_基于HTTP 协议的网络应用程序

文章目录 1. 实现高层网络操作的类2. 基于HTTP协议的网络文件下载3.源码3.1 可是化UI设计3.2 mainwindow.h3.3 mainwindow.cpp 1. 实现高层网络操作的类 Qt 网络模块提供一些类实现 OSI 7 层网络模型中高层的网络协议&#xff0c;如 HTTP、FTP、SNMP等&#xff0c;这些类主要是…

Netty使用和常用组件辨析

Netty 使用和常用组件 简述 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId <version>4.1.42.Final </version> <scope>compile</scope> </dependency> Netty 的优势 1 、 AP…

【小吉带你学Git】idea操作(2)_版本和分支的相关操作

&#x1f38a;专栏【Git】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;版本⭐首先创建一个项目⭐添加暂存区⭐提交本地库&#x1f33…

压力测试与测试工具jmeter的介绍

目录 一、性能指标 二、jmeter &#xff08;一&#xff09;JMeter 安装 &#xff08;二&#xff09;JMeter 压测示例 1、添加线程组 2、添加 HTTP 请求 3、添加监听器 4、启动压测&查看分析结果 &#xff08;三&#xff09;JMeter Address Already in use 错误解决 压力测…

yum出现Could not retrieve mirrorlist解决方法

Loaded plugins: fastestmirror, security Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirrorlist.centos.org/?release6&archi386&repoos error was 14: PYCURL ERROR 6 - “Couldn’t resolve host ‘mirrorlist.centos.org…

【web逆向】全报文加密及其登录流程的分析案例

aHR0cHM6Ly9oZWFsdGguZWxkZXIuY2NiLmNvbS9zaWduX2luLw 涉及加密库jsencrypt 定位加密点 先看加密的请求和响应&#xff1a; 全局搜索加密字段jsondata&#xff0c;这种非特定参数的一般一搜一个准&#xff0c;搜到就是断点。起初下的断点没停住&#xff0c;转而从调用栈单步…

K8S系列文章之 kubeasz部署K8S环境

自动化安装方式&#xff08;kubeasz&#xff09;* 生产环境推荐&#xff08;首次安装下载相关配置和安装包&#xff09;是基于Ansible实现的部署工具 简单介绍 每一具体k8s集群的详细配置参数文件 Ansible 任务配置文件 镜像安装包 安装部署步骤 前提 &#xff1a; 保证Ansib…

Python web实战之 Django 的模板语言详解

关键词&#xff1a; Python、web开发、Django、模板语言 概要 作为 Python Web 开发的框架之一&#xff0c;Django 提供了一套完整的 MVC 模式&#xff0c;其中的模板语言为开发者提供了强大的渲染和控制前端的能力。本文介绍 Django 的模板语言。 1. Django 模板语言入门 Dj…

npm发布包

1.npm 登录 在控制台输入命令 npm login 按提示输入用户名&#xff0c;密码&#xff0c;邮箱后登录 如果出现如下提示 需要将淘宝镜像源切换为npm源&#xff0c;删除或注释以下内容就行 2.发布 进入准备发布的代码的根目录下&#xff0c;输入命令 npm publish 3.删除已发…

怎么学习CSS相关技术知识? - 易智编译EaseEditing

学习CSS技术是前端开发中的重要一环&#xff0c;它用于控制网页的样式和布局&#xff0c;使网页更加美观和易于使用。以下是学习CSS技术的几个方面&#xff1a; 基本语法和选择器&#xff1a; 了解CSS的基本语法&#xff0c;学习如何使用选择器来选择HTML元素并应用样式。 样…

一条sql语句在mysql中如何执行(查询+更新)

文章目录 一 MySQL 基础架构1.1 MySQL 基本架构1.2 Server 层基本组件介绍1) 连接器2) 查询缓存(MySQL 8.0 版本后移除)3) 分析器4) 优化器5) 执行器 二 语句分析2.1 查询语句2.2 更新语句为什么要用两个日志模块&#xff0c;用一个日志模块不行吗?为什么必须有“两阶段提交”…

MySQL的索引使用的数据结构,事务知识

一、索引的数据结构&#x1f338; 索引的数据结构&#xff08;非常重要&#xff09; mysql的索引的数据结构&#xff0c;并非定式&#xff01;&#xff01;&#xff01;取决于MySQL使用哪个存储引擎 数据库这块组织数据使用的数据结构是在硬盘上的。我们平时写的代码是存在内存…

MyCat核心概念、需求案例讲解、环境准备及分片配置

1.MyCat概念介绍 2.MyCat入门需求 2.1 需求分析 2.2 环境准备 输入以下命令检查服务器防火墙状态 dead代表关闭状态&#xff0c;如果不关闭也可以需要开放特定的端口号&#xff01;&#xff01; systemctl status firewalld接着需要在三台服务器上的MySQL上创建三个数据库db0…

企业架构NOSQL数据库之MongoDB

目录 一、背景描述及其方案设计 (一)业务背景描述 &#xff08;二&#xff09;模拟运维设计方案 二、Mongodb介绍 &#xff08;一&#xff09;nosql介绍 &#xff08;二&#xff09;产品特点 1、存储性 2、 效率性 3、结构 三、安装和配置 &#xff08;一&#xff09…

Leetcode-每日一题【剑指 Offer 10- I. 斐波那契数列】

题目 写一个函数&#xff0c;输入 n &#xff0c;求斐波那契&#xff08;Fibonacci&#xff09;数列的第 n 项&#xff08;即 F(N)&#xff09;。斐波那契数列的定义如下&#xff1a; F(0) 0, F(1) 1 F(N) F(N - 1) F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 开…

[openCV]基于赛道追踪的智能车巡线方案V1

import cv2 as cv import os import numpy as npimport time# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir&#xff1a;文件夹根目录输入 ext: 扩展名返回&#xff1a; 文件路径列表""&quo…