[Linux]进程间通信

[Linux]进程间通信

文章目录

      • [Linux]进程间通信
        • 进程间通信
          • 什么是进程间通信
          • 进程间通信的目的
          • 进程间通信的本质
          • 为什么存在进程间通信
          • 进程间通信的分类
        • 管道
          • 什么是管道
          • 匿名管道
            • 本质
            • pipe
            • pipe的使用
            • 匿名管道读写情况
            • 匿名管道的特征
          • 命名管道
            • 本质
            • 命令行创建命名管道
            • 创建和删除命名管道
            • 实现服务端与客户端通信
        • System V
          • system V共享内存
            • 共享内存的原理
            • IPC资源的查看
            • 共享内存的创建和释放
            • 共享内存的关联和去关联
            • 实现服务端与客户端通信

进程间通信

什么是进程间通信

进程之间具有独立性,如果需要进行通信,就必须打破进程间的独立性。进程通信需要提供一块公共的能够进行信息存储和取出的空间。文件系统提供的我们称为管道,操作系统提供的System V。

进程间通信的目的
  1. 数据传输:一个进程将数据发送给另一个进程。
  2. 资源共享:多个进程共享相同的资源。
  3. 事件通知:一个进程需要向另一个或一组进程发送消息。通知它们发生了某种事件,例如子进程终止时需要通知父进程。
  4. 进程控制:有的进程希望完全控制另一个进程的执行,例如Debug进程。
进程间通信的本质

进程间通信的本质就是让不同的进程看到同一份资源。

实际上就是构建一个公共区域,供不同进程进行写入或读取数据。

image-20230727104753581

为什么存在进程间通信

实际情况中,有时候我们需要多进程协作完成某种业务。

进程间通信的分类
  1. 管道
  • 匿名管道
  • 命名管道
  1. System V
  • System V消息队列
  • System V信号量
  • System V共享内存
  1. POSIX
  • 共享内存
  • 信号量
  • 消息队列
  • 互斥量
  • 条件变量
  • 读写锁

管道

什么是管道
  • 管道是Unix中最古老的进程间通信的形式。
  • 我们把从一个进程连接到另一个进程的数据流称为一个“管道”。

其实我们早在之前命令中的学习就已经见过了管道|,我们也经常使用管道命令。

例如,查看服务器连接人数:

[---@VM-8-4-centos day04]$ who | wc -l

image-20230727110434843

在这里插入图片描述

匿名管道
本质

匿名管道主要用于父子间的通信。它本质上就是让父子进程看到同一个被打开的文件,然后让父子进程进行写入或读取数据,从而实现父子间的通信。

这里的文件是由操作系统提供的,所以在父进程或子进程写入数据时,并不会发生写时拷贝。

pipe
int pipe(int pipefd[2]);
  • 头文件:#include<unistd.h>
  • pidfd是一个输出型参数,pipfd[0]:管道读端的文件描述符;pipfd[1]:管道写端的文件描述符。
  • 返回值:调用成功,返回0;调用失败,返回-1。
pipe的使用

实际上,我们需要对一对父子进程关闭相反的两个端口来使用匿名管道进行通信。

  • 需要父进程读,则关闭父进程的写端和关闭子进程的读端。
  • 需要父进程写,则关闭父进程的读端和关闭子进程的写端。

例如,父进程关闭写端,子进程关闭读端。

#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cstring>#include <sys/types.h>
#include <sys/wait.h>
using namespace std;int main()
{int fd[2] = {0};int n = pipe(fd);if (n != 0)perror("pipe fail");pid_t id = fork();int cnt = 0;const char *str = "I am a child process. MYPID->";if (id > 0){close(fd[1]); // 父进程关闭写端while (1){char buffer[1024];ssize_t r = read(fd[0], buffer, sizeof(buffer) - 1);if (r > 0){buffer[r] = '\0';cout << "parent process get message-> " << buffer << endl;}else if (r == 0){// 读完了cout << endl;cout << "数据读取完毕!!!" << endl;break;}else{perror("read fail");return -1;}}int wp = waitpid(-1, nullptr, 0);close(fd[0]);return 0;}else if (id == 0){close(fd[0]); // 子进程关闭读端while (1){char buffer[1024];snprintf(buffer, sizeof(buffer), "Message: %s%d, count: %d", str, getpid(), cnt++);write(fd[1], buffer, strlen(buffer));sleep(1); // 每隔1秒写入一次if (cnt == 6)break;}close(fd[1]);exit(0);}else{perror("fork fail");return -1;}return 0;
}

在这里插入图片描述

匿名管道读写情况
  1. 如果管道中没有数据,读端进行读取,就会阻塞当前读取的进程
  2. 如果写端写满了,写端还进行写入,就会阻塞当前写端的进程
  3. 如果写端关闭了,读端读完数据后就会返回0,正常退出
  4. 如果读端关闭了,操作系统会向写端发送13号信号SIGPIPE,从而让写端关闭
匿名管道的特征
  1. 匿名管道是半双工通信的。
  • 单工通信:数据传输在通信双方是单向的,一方为固定发送端,另一方为固定接收端。
  • 半双工通信:数据传输在通信双方是双向的,但不能同时发送数据。
  • 全双工通信:数据传输在通信双方是双向的,允许同时发送数据。
  1. 管道的生命周期随进程,进程退出,则管道释放。
  • 管道的本质是通过一个文件进行通信的,当打开这个文件的进程退出后,这个文件也会被释放掉。
  1. 管道提供的是流式服务。
  • 对于写端写入的数据,读端读取的数据是任意的,这就是流式服务。
  • 对于写端写入的数据,读端读取时根据数据的分割(按一定的报文段)读取,这就是与流式服务相对的数据报服务。
  1. 内核对管道操作会进行同步和互斥。
  • 同步:在特定的时间点或条件下,不同进程之间的操作按照一定的顺序和速度进行,以保证它们之间的状态和行为达到预期的一致性。
  • 互斥:一个公共资源同一时刻只能被一个进程使用,多个进程不能同时使用公共资源。

对于管道来说,同步就是指这两个进程不能同时对管道进行操作,但这两个进程必须要按照某种次序来对管道进行操作;互斥就是两个进程不可以同时对管道进行操作,它们会相互排斥,必须等一个进程操作完毕,另一个才能操作。

ps:管道的最大容量一般是65536字。

我们也可以通过以下命令查看:

[---@VM-8-4-centos day04]$ ulimit -a

image-20230727210011484

命名管道

匿名管道通常只能用于父子进程间的通信,为了让不具有亲缘关系的进程相互通信,由此有了命名管道。

本质

通过创建一个特殊的文件,让两个进程看到同一份资源,从而实现通信。

匿名管道和命名管道都是内存文件,但是命名管道在磁盘上有一个特殊的映像。(大小为0,因为命名管道和匿名管道都不会刷新到磁盘上)

命令行创建命名管道
[---@VM-8-4-centos day04]$ mkfifo named_pipe

image-20230727211628264

我们可以从第一个p看到出,这个文件类型是管道文件,管道文件大小默认是0。

此时我们已经可以进行通信了,我们使用两个不同的命令行进行通信测试:

image-20230727212134864

如果我们不进行读取,写端就会阻塞等待读端读取。

创建和删除命名管道
int mkfifo(const char *pathname, mode_t mode);
  • pathname:命名管道创建路径,若给出文件名,则创建在当前路径下;若给出路径,按路径创建

  • mode:管道文件默认权限

  • 返回值:创建成功,返回0;创建失败,返回-1。

image-20230727214411219

image-20230727214428861

int main()
{umask(0);int n = mkfifo("named_pipe", 0666);if(n < 0) perror("mkfifo fail");//创建成功cout << "mkfifo success..." << endl;return 0;
}

image-20230727215445358

int unlink(const char *path)
  • path:管道路径
  • 返回值,创建成功,返回0;创建失败,返回-1

image-20230728104124115

image-20230728104145636

int main()
{int n = unlink("./named_pipe");if(n == -1) {perror("unlink fail");return -1;}cout << "unlink success ......." << endl;return 0;
}

image-20230728104530341

实现服务端与客户端通信

com.hpp

#pragma once
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>using namespace std;bool create_named_pipe()
{umask(0);int n = mkfifo("./named_pipe", 0600); // 创建管道文件if (n != 0){perror("mkfifo fail");return false;}cout << "mkfifo success ......" << endl;return true;
}void unlink_named_pipe()
{int n = unlink("./named_pipe");if (n != 0)perror("unlink fail");cout << "unlink success ......" << endl;
}

serve.cc

#include "com.hpp"int main()
{bool flag = create_named_pipe();if (flag == false){perror("create_named_pipe fail");exit(-1);}int fd = open("./named_pipe", O_RDONLY);if (fd < 0)perror("open fail");char buffer[1024];while (1){ssize_t r = read(fd, buffer, sizeof(buffer) - 1);if (r > 0){buffer[r] = '\0';cout << "serve get message -> " << buffer << endl;}else if (r == 0){cout << "read end ......" << endl;break;}else{perror("read fail");return -1;}}close(fd);unlink_named_pipe();return 0;
}

client.cc

#include "com.hpp"int main()
{int fd = open("./named_pipe", O_WRONLY);if (fd < 0)perror("open fail");char buffer[1024];while(1){cout << "client Enter # ";fgets(buffer, sizeof(buffer), stdin);//fgets剩一个空间会被系统填充'\0',不用-1ssize_t w = write(fd, buffer, strlen(buffer));if(w != strlen(buffer)){perror("write fail");exit(-1);}}close(fd);return 0;
}

image-20230728224245270

另外一提,命令行中的管道|是匿名管道。

System V

之前我们提到过System V通信方式有:System V共享内存、System V消息队列、System V信号量,下面我们就着重说说System V共享内存。

system V共享内存
共享内存的原理

用户使用操作系统提供的接口在物理内存中申请一块资源,通过页表将这段物理空间映射至进程地址空间,进程将这段虚拟地址的起始地址返回给用户。

image-20230728110710348

操作系统中的进程都可以通过共享内存进行通信,一个操作系统可以有多个共享内存。

共享内存不止一个,操作系统必然对这些共享内存也要进行管理,系统也为他维护了一个数据结构:

struct shmid_ds {struct ipc_perm     shm_perm;   /* operation perms */int         shm_segsz;  /* size of segment (bytes) */__kernel_time_t     shm_atime;  /* last attach time */__kernel_time_t     shm_dtime;  /* last detach time */__kernel_time_t     shm_ctime;  /* last change time */__kernel_ipc_pid_t  shm_cpid;   /* pid of creator */__kernel_ipc_pid_t  shm_lpid;   /* pid of last operator */unsigned short      shm_nattch; /* no. of current attaches */unsigned short      shm_unused; /* compatibility */void            *shm_unused2;   /* ditto - used by DIPC */void            *shm_unused3;   /* unused */
};

第一个成员shm_perm的类型ipc_perm结构是这样的。(key也存在shm_perm中)

struct ipc_perm{__kernel_key_t  key;__kernel_uid_t  uid;__kernel_gid_t  gid;__kernel_uid_t  cuid;__kernel_gid_t  cgid;__kernel_mode_t mode;unsigned short  seq;
};
IPC资源的查看

我们使用以下命名,可以查看系统中的IPC资源:

[---@VM-8-4-centos day05]$ ipcs

在这里插入图片描述

ipcs这个命令还有3个选项,分别来查看共享内存、消息队列和信号量。

  • -q:仅显示消息队列的信息
  • -m:仅显示共享内存的信息
  • -a:仅显示信号量的信息
共享内存的创建和释放
key_t ftok(const char *pathname, int proj_id);
  • 作用:将一个存在且可获取的路径名pathname和一个整数标识符proj_id转换成一个key值,称为IPC键值,方便共享内存创建唯一标识。
  • 返回值:创建成功,返回key值;创建失败,返回-1。

image-20230728112857273

image-20230728112914784

int shmget(key_t key, size_t size, int shmflg);
  • key:形成唯一标识,保证进程看到的是同一块共享内存。(使用ftok获取)
  • size:创建共享内存的大小。
  • shmflg:共享内存的创建方式。IPC_CREAT:共享内存不存在,则创建,如果存在则获取;IPC_EXCL:无法单独使用,IPC_CREAT|IPC_EXCL:如果不存在就创建,如果存在就出错返回。(记得设置权限0666等,例如IPC_CREAT | IPC_EXCL | 0666)
  • 返回值:创建成功,返回共享内存标识符;创建失败,返回-1。

image-20230728113015896
image-20230728113106487

#include <iostream>
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <unistd.h>using namespace std;int main()
{key_t key = ftok("./makefile", 0x6666);if(key < 0) {perror("ftok fail");return -1;}int shm = shmget(key, 4096, IPC_CREAT | IPC_EXCL);if(shm < 0){perror("shmget fail");return -2;}cout << key << endl << shm << endl;return 0;
}

image-20230728112809018

我们使用ipcs命令来看一下,我们是否创建成功:

在这里插入图片描述


int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • shmid:表示所控制共享内存的用户级标识符。
  • cmd:表示具体的控制动作。IPC_RMID最为常用,表示删除共享内存。
  • buf:用于获取或设置所控制共享内存的数据结构。一般设置为nullptr
  • 返回值:调用成功,返回0;调用失败。返回-1。

image-20230728113720899

image-20230728113747665

int main()
{key_t key = ftok("./makefile", 0x6666);if (key < 0){perror("ftok fail");return -1;}int shm = shmget(key, 4096, IPC_CREAT | IPC_EXCL);if (shm < 0){perror("shmget fail");return -2;}cout << key << endl << shm << endl;cout << "create success..." << endl;sleep(3);int ctl = shmctl(shm, IPC_RMID, nullptr);if(ctl < 0){perror("shmctl fail");return -3;}cout << "delete success..." <<endl;return 0;
}

我们创建一块共享内存,让程序休眠3秒。休眠后,删除这块共享内存。(我们可以看见其中有3行打印了这块共享内存,第4行就没有了,这也证明了我们代码的逻辑是正确的)

右边命令行使用以下的监控脚本:

[wsj@VM-8-4-centos day05]$ while :; do ipcs -m;echo "###################################";sleep 1;done

image-20230728180549070


我们也可以使用命令行来删除共享内存:

[wsj@VM-8-4-centos day05]$ ipcrm -m 6(数字代表自己共享内存的shm)

image-20230728181119102

共享内存的关联和去关联
void *shmat(int shmid, const void *shmaddr, int shmflg);
  • shmid:待关联的共享内存标识符
  • shmaddr:指定共享内存映射到进程地址空间中的某一地址,一般设置nullptr让内核自己选择。
  • shmflg:SHM_RDONLY,表示关联共享内存后,仅进行读取操作;SHM_RND,表示如果shmaddr不为空,则自动向下调整为SHMLBA的整数倍;0,默认为读写权限。
  • 返回值:调用成功,返回映射到进程地址空间的共享内存的地址;调用失败,返回(void*)-1。
int shmdt(const void *shmaddr);
  • shmaddr:待去关联的共享内存,使用shmat得到的地址。

  • 返回值,调用成功,返回0;调用失败,返回-1。

接下来,我们使用一段代码加深一下对这些接口调用的理解:

int main()
{key_t key = ftok("./makefile", 0x6666);if (key < 0){perror("ftok fail");return -1;}int shm = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0666);if (shm < 0){perror("shmget fail");return -2;}cout << "create success..." << endl;cout << "-----------------------" << endl;void* mem = shmat(shm, nullptr, 0);if(mem == (void*)-1){perror("shmat fail");return -3;}cout << "attach success..." << endl;cout << "-----------------------" << endl;int dt = shmdt(mem);if(dt < 0){perror("shmdt fail");return -4;}cout << "detach success ..." << endl;cout << "-----------------------" << endl;int ctl = shmctl(shm, IPC_RMID, nullptr);if(ctl < 0){perror("shmctl fail");return -5;}cout << "delete success..." << endl;return 0;
}

右边的命令行,任然使用上面的监控脚本。

我们从共享内存,从无到有;从关联数,从0到1,再到0。证明我们代码的逻辑是正确的。(创建共享内存->关联该共享内存->去关联该共享内存->删除共享内存)

image-20230728184614542

ps:创建共享内存时需要设置权限,不然就无法正常关联。

image-20230728185006918

实现服务端与客户端通信

com.hpp

#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>using namespace std;#define PATH "./makefile"
#define PROJ_ID 0X888
#define MAX_SIZE 4096key_t getKey() // 获取key值
{key_t key = ftok(PATH, PROJ_ID);if (key == -1){perror("ftok fail");exit(-1);}return key;
}int getShm(key_t key, int flag) // 创建共享内存,为下面两个函数服务
{int shm = shmget(key, MAX_SIZE, flag);if (shm < 0){perror("shmget fail");exit(-2);}return shm;
}int shmHelper(key_t key) // 获取共享内存(已创建的前提)
{return getShm(key, IPC_CREAT);
}int createShm(key_t key) // 创建共享内存
{return getShm(key, IPC_CREAT | IPC_EXCL | 0666);
}void *attachShm(int shm) // 关联
{void *mem = shmat(shm, nullptr, 0);if (mem == (void *)-1){perror("shmat fail");exit(-3);}return mem;
}void detachShm(void *mem) // 去关联
{if (shmdt(mem) < 0){perror("shmdt fail");exit(-4);}
}int deleteShm(int shm) // 删除共享内存
{if (shmctl(shm, IPC_RMID, nullptr) < 0){perror("shmctl fail");exit(-5);}
}

serve.cc

#include "com.hpp"int main()
{int key = getKey();int shm = createShm(key);cout << shm << endl;void *mem = attachShm(shm);cout << mem << endl;int cnt = 0;while (cnt++ < 10){printf("client # %s\n", mem);struct shmid_ds ds;shmctl(shm,IPC_STAT,&ds);cout << "PID->" << getpid() << ", creator->" << ds.shm_cpid << ", key->" << ds.shm_perm.__key << endl;sleep(1);}detachShm(mem);deleteShm(shm);return 0;
}

client.cc

#include "com.hpp"int main()
{int key = getKey();int shm = shmHelper(key);cout << shm << endl;void *mem = attachShm(shm);cout << mem << endl;int cnt = 0;char *message = "Hello, I`m client";while (1){snprintf((char *)mem, MAX_SIZE, "PID->%d : %s, count : %d\n", getpid(), message, ++cnt);sleep(1);}detachShm(mem);return 0;
}

image-20230728223930542

共享内存是所有通信中最快的通信方式,因为它没有缓冲区,能大大减少通信数据的拷贝次数。

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

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

相关文章

如何在电脑上查看连接过的wifi信息?

忘记wifi密码&#xff1f;想要看看wifi信息&#xff1f; 我想这篇文章可以帮到你O(∩_∩)O哈哈~。 通过网络连接中心查看 电脑上找到“网络和共享中心” 点击连接的wifi名称 点击无线属性 在安全选项中就有密码 通过电脑命令行工具查看推荐 通过winr快捷键打开电脑运…

手动搭建gateway,项目集成gateway实现Token效果

目录 背景步骤1、首先创建springboot项目2、引入依赖3、配置文件&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff08;超级重要&#xff01;&#xff01;&#xff01;根据自己的需要进行配置&#xff09;4、相关类我们在服务中进行的白名单中接口的操作如…

信驰达推出RTL8720DN系列2.4G和5G双频Wi-Fi+蓝牙二合一模块

近日&#xff0c;领先的无线物联网通信模块厂商深圳信驰达科技RF-star推出了基于RTL8720DN SoC的2.4 GHz和5 GHz双频Wi-Fi蓝牙二合一模块—RF-WM-20DNB1。 图 1信驰达RF-WM-20DNB1 Wi-Fi模块 RF-WM-20DNB1是一款低功耗单芯片无线蓝牙和Wi-Fi组合模块&#xff0c;支持双频(2.4 G…

详细介绍如何使用HuggingFace和PyTorch进行医学图像分割-附源码

医学图像分割是一种创新过程,使外科医生能够拥有虚拟的“X 射线视觉”。它是医疗保健领域非常有价值的工具,可提供非侵入性诊断和深入分析。考虑到这一点,在这篇文章中,我们将探索威斯康辛大学麦迪逊分校胃肠道图像分割Kaggle 挑战数据集。作为该项目的一部分,我们将使用 …

爬虫005_python类型转换_其他类型转换为整型_转换为Float类型_转换为字符串_转换为布尔值---python工作笔记023

首先来看,字符串转换成int 很简单 float转换成int 会把小数点后面的内容丢掉 boolean转换为int true是1 false 是0 然后字符串转换为int,要注意 不能有特殊字符比如1.23 中有点 就报错 上面字符串12ab,有ab也报错 看上面

Docker可视化管理工具Portainer多机器安装使用

一、首先得安装docker Docker安装并指定主目录:https://blog.csdn.net/wdy_2099/article/details/77367107 二、使用docker方式安装portainer 安装命令如下&#xff1a; docker run -it -d \-p 8999:9000 \--name portainer \--restart always \-v /var/run/docker.sock:/v…

Linux Ubuntu crontab 添加错误 提示:no crontab for root - using an empty one 888

资料 错误提示&#xff1a; no crontab for root - using an empty one 888 原因剖析&#xff1a; 第一次使用crontab -e 命令时会让我们选择编辑器&#xff0c;很多人会不小心选择默认的nano&#xff08;不好用&#xff09;&#xff0c;或则提示no crontab for root - usin…

【图像分类】CNN + Transformer 结合系列.1

介绍三篇结合使用CNNTransformer进行学习的论文&#xff1a;CvT&#xff08;ICCV2021&#xff09;&#xff0c;Mobile-Former&#xff08;CVPR2022&#xff09;&#xff0c;SegNetr&#xff08;arXiv2307&#xff09;. CvT: Introducing Convolutions to Vision Transformers, …

Windows bat 查找文件被哪个进程占用,并终止该进程

一、背景 我有个批处理脚本如下&#xff1a; echo off chcp 936 & cls cd /D F:\Chen\python3\ExciseC set fdate%date:~0,4%%date:~5,2%%date:~8,2% python main.py >> crawl_record_%fdate%.log 2>&1 for /F %%f in (dir crawl_record_*.log /B ^| find /…

机器学习——异常检测

异常点检测(Outlier detection)&#xff0c;⼜称为离群点检测&#xff0c;是找出与预期对象的⾏为差异较⼤的对象的⼀个检测过程。这些被检测出的对象被称为异常点或者离群点。异常点&#xff08;outlier&#xff09;是⼀个数据对象&#xff0c;它明显不同于其他的数据对象。异…

Linux工具【1】(编辑器vim、编译器gcc与g++)

vim详解 引言vimVim的三种模式及模式切换普通模式下操作底行模式下操作 gcc与ggcc的使用&#xff08;g类似&#xff09;预编译编译汇编链接静态库与动态库 总结 引言 vim&#xff08;vi improved&#xff09;编辑器是从 vi 发展出来的一个文本编辑器。 代码补全、编译及错误跳…

opencv python 训练自己的分类器

源码下载 一、分类器制作 1.样本准备 收集好你所需的正样本&#xff0c;和负样本&#xff0c;分别保存在不同文件夹 在pycharm新建项目&#xff0c;项目结构如下&#xff1a;has_mask文件夹放置正样本&#xff0c;no_mask文件夹放置负样本 安装opencv&#xff0c;把opencv包…

Day.4 刷题练习(自守数)

题目&#xff1a; 例子&#xff1a; 分析题目&#xff1a; 主要目的&#xff1a;给定一个范围小于等于N&#xff0c;在这个范围中找自守数&#xff08;自身等于平方后的尾部数据如5&#xff1a;5 ^ 2 25 &#xff0c; 然后 5 与 平方的后的尾部相等&#xff09; 思路&#x…

ancos注册中心、网关和静态化freemarker、对象存储服务MinIO

1、docker安装ancos ①&#xff1a;docker拉取镜像 docker pull nacos/nacos-server:1.2.0②&#xff1a;创建容器 docker run --env MODEstandalone --name nacos --restartalways -d -p 8848:8848 nacos/nacos-server:1.2.0③&#xff1a;访问地址&#xff1a;http://192…

Qt : day4

1.思维导图 2.服务器 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//给服务器指针实例化空间server new QTcpServer(this);}Widget::~Widget() {delete ui;…

下级平台级联视频汇聚融合平台EasyCVR,层级显示不正确的原因排查

视频汇聚平台安防监控EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、WebRTC等…

【计算机网络】第 3 课 - 计算机网络体系结构

欢迎来到博主 Apeiron 的博客&#xff0c;祝您旅程愉快 &#xff01; 时止则止&#xff0c;时行则行。动静不失其时&#xff0c;其道光明。 目录 1、常见的计算机网络体系结构 2、计算机网络体系结构分层的必要性 2.1、物理层 2.2、数据链路层 2.3、网路层 2.4、运输层 2…

Sentinel nacos spring cloud 持久化配置---分布式/微服务流量控制

文章目录 sentinel控制台安装目标实现代码地址版本说明maven spring-cloud-starter-alibaba-sentinel依赖yml文件Nacos业务规则配置看源码配置规则SentinelProperties 总配置加载DataSourcePropertiesConfiguration 配置标准的nacos配置注册具体sentinel配置 外传 sentinel控制…

Chrome 115 有哪些值得关注的新特性?

今天带大家一起来了解一下 Chrome 115 值得关注的新特性。 滚动动画 用滚动驱动的动画是网站上非常常见的用户体验模式&#xff0c;比如当页面向前或向后滚动时&#xff0c;对应的动画也会向前或向后移动。 比如下面图中这种比较常见的&#xff0c;页面顶部的进度条随着滚动…

华为OD机试真题 Java 实现【数字涂色】【2022Q4 100分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 刷的越多&…