Linux 进程通信

news2024/9/28 7:24:25

文章目录

  • 匿名管道
    • 匿名管道使用
    • 匿名管道原理
    • 匿名管道读写
  • 命名管道
    • 命名管道使用
    • 命名管道特性
  • 共享内存
    • 共享内存原理
    • 共享内存使用
  • 补充说明

补充说明部分为相关函数和不太重要的概念介绍

匿名管道

匿名管道使用

使用方法一:
使用函数介绍:

#include <unistd.h>
功能:创建一无名管道
原型:
int pipe(int fd[2]);
参数:
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码

简单的父子进程通过管道通信范例:

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

 int main() 
 {
 	int pipefd[2]; 
 	if (pipe(pipefd) == -1)
 	{
 	 perror("pipe error");
 	 exit(-1);
 	}
 	pid_t pid;
 	pid = fork();
 	
 	if (pid == -1)
 	{
 		perror("fork error");
 		exit(-2);
 	}
 	if (pid == 0) 
 	{
 		close(pipefd[0]);
 		write(pipefd[1], "hello", 5);
 		close(pipefd[1]);
 		exit(1); //子进程成功运行
 	}
 	close(pipefd[1]);
 	char buf[10] = {0};
 	//read(pipefd[0], buf, 10);
	while(read(pipefd[0], buf, 10)) 
	{
		// 这样写的原因,见匿名管道的读写部分。
	}

 	printf("buf=%s\n", buf);
 
 	return 0;
}

使用方法二:
使用管道操作符 |
Linux命令行中的管道操作符本质上就是创建了一个匿名管道,将前一个进程的结果发送给下一个进程。

匿名管道原理

上述代码中,利用管道进行进程间通信,虽然是利用文件描述符的形式进行读写,但实际上并没有创建实际的文件,并没有实际消耗磁盘空间。 实际上匿名管道是一个内核缓冲区,存储在内存之上。管道自动销毁的机制,是读写两端,也就是父子进程都关闭了文件描述符,操作系统为了避免资源浪费,自动的销毁了管道。

指令管道:

在这里插入图片描述
代码管道:
在这里插入图片描述
父子进程通关管道通信原理图

在这里插入图片描述
操作系统视角下的匿名管道父子进程通讯:
在这里插入图片描述

匿名管道读写

读写规则:

  1. 文件描述符设置为阻塞且管道为空时: read阻塞,进程阻塞,直到管道内有数据被输入。
  2. 文件描述符设置为非阻塞且管道为空时:read函数执行失败返回值为-1。
  3. 对端管道文件描述符关闭,read函数执行返回值为0。 如果管道内容还有内容,会将剩余的内容读完,并在下一次调用返回为0,因为本质上是read读到第一个文件结尾的标志位从而判断对端退出。
  4. 文件描述符设置为阻塞且管道为满时 :write阻塞,进程组设,直到管道内内容被取走。
  5. 文件描述符设置为非阻塞为满时:write函数执行失败返回值为-1.
  6. 对端管道文件描述符关闭,write产生SIGPIPE信号,可能导致write进程退出。
  7. 如果write写入管道的数据大于管道存储空间大小,则要写入的数据会分次写入管道,无法保证原子性。 如果write写入管道的数据小于管道存储空间大小,则要写入的数据会一次性写入管道,保证原子性。
  8. 进程退出,则管道释放。
  9. 匿名管道的通信被局限于有情缘关系的进程直接。
  10. 对于同一管道不能同时读写。

命名管道

命名管道使用

利用mkfifo函数(见补充说明部分)创建命名管道范例:

读取端:

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

int main()
{
    if(mkfifo("./testFileName", O_RDONLY) < 0 ) // 成功时返回0,失败时返回-1
    {
        perror("mkfifo error");
        exit(-1);
    }

    int input = open("./testFileName", O_RDONLY) ; 
    if(0 > input)
    {
        perror("open error");
        exit(-1) ;
    }

    char buf[1024];

    while(true)
    {
        buf[0] = 0;
        printf("Please wait...\n");
        ssize_t s = read(input, buf, sizeof(buf)-1);
        if(s > 0 )
        {
            buf[s-1] = 0;
            printf("client say# %s\n", buf);
        }
        else if(s == 0)
        {
            printf("client quit, exit now!\n");
            exit(1);
        }
        else
        {
            perror("read");
            exit(-1);
        }
    }

    close(input) ; 
    return 0  ;
}

写入端:

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

int main()
{
    int output = open("./testFileName", O_WRONLY);
    char buf[1024] ;

    while (true)
    {
        buf[0] = 0 ; 
        ssize_t s = read(0, buf, sizeof(buf)-1);
        if(s > 0)
        {
            if(0 > write(output, buf, sizeof buf - 1))
            {
                perror("write error\n");
                exit(-1);
            }
        }
        else
        {
            perror("read error");
            exit(-1);
        }
    }
    
    close(output);
    return 0 ; 
}

命名管道特性

O_NONBLOCK是文件描述符的属性
对于读操作:
当文件描述符属性设置为O_NONBLOCK时,读取操作立刻返回,无论是否有其他进程以写方式打开进程,如果管道文件中没有数据可读,那么读取操作将返回错误码,表示没有数据可读。 如果设置为非O_NONBLOCK时,阻塞到直到有相应的进程为写而打开该管道文件。
对于写操作:
当文件描述符被设置为O_NONBLOCK时,写操作立刻失败,并设置错误码。当文件描述符设置为非O_NONBLOCK时,阻塞到直达有进程为读操作而打开管道文件

共享内存

共享内存原理

共享内存本质是将要通讯的两个进程之间的进程地址空间映射到同一块物理内存中,共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。 共享内存的管理也是先描述再组织的,描述的结构体为shmid_ds结构体。

struct shmid_ds 结构体定义

struct shmid_ds 
{
    struct ipc_perm shm_perm;  // 共享内存的权限信息
    size_t shm_segsz;          // 共享内存的大小(字节)
    time_t shm_atime;          // 上次访问时间
    time_t shm_dtime;          // 上次分离时间
    time_t shm_ctime;          // 上次变更时间
    pid_t shm_cpid;            // 创建共享内存的进程ID
    pid_t shm_lpid;            // 最后一次操作共享内存的进程ID
    unsigned short shm_nattch; // 当前附加到共享内存的进程数
}

共享内存原理图
先上原理图

此外使用 ipcs -m指令可查看操作系统上所有的共享内端信息。
在这里插入图片描述

利用指令ipcrm -m + shmid 即可删除指定shmid的共享内存。

共享内存使用

利用共享内存实现server端和client端通信代码例子

代码逻辑:

./server —> ftok(依据路径和自定义ID生成key,key作为生成共享内存的参数) —>
shmet(生成共享内存) —> shmat(将共享内存与该进程绑定,得到用于使用共享内存的指针) —> 使用指针进行读取共享内存中的内容 ——> shmdt(解除共享内存和本进程的绑定) —>
shmctl(销毁共享内存) —> 结束

server先启动 —> client启动 —> shmget(只用IPC_CREAT选项,如果用了IPC_EXCL就会报错) —> 得到共享内存shmid —> shmat(将共享内存与该进程绑定,得到用于使用共享内存的指针) ——> 使用指针进行向共享内存中写入内容 shmdt(解除共享内存和本进程的绑定) —> 结束

#include "comm.hpp"

static int commShm(int size , int falgs)
{
    // ftok为生成进程通信键值的函数
    // 参数相同会生成一样的key  
  // 导致的效果就是两个进程调用该函数得到是同一块共享内存!
    // PROJ_ID/PATHNAME为宏定义
    key_t key = ftok(PATHNAME, PROJ_ID) ; 
    if(0 > key)
    {
        perror("ftok error");
        return -1 ;
    }

    int shmid ;
    //参数: key  共享内存大小  权限 


	//flage: IPC_CREAT(创建共享内存段)和 IPC_EXCL
	//(与 IPC_CREAT 一起使用,确保创建一个新的共享内存段)。
	//0666为共享内存权限
    if(0 > (shmid = shmget(key, size, falgs)) )
    {
        perror("shmget error");
        return -1 ; 
    }

    return shmid ;
}

int destroyShm(int shmid)
{
    if(shmctl(shmid, IPC_RMID, NULL) < 0)
    {
        perror("shmctl error\n"); 
        return -1 ;
    }

    printf("\n ipc destory success \n") ;
    return 0  ;
}


int createShm(int size)
{
    //IPC_CREAT表示如果共享内存不存在,则创建一个新的共享内存;IPC_EXCL表示如果共享内存已经存在,则创建失败;
    return commShm(size, IPC_CREAT | IPC_EXCL | 0666) ; 
}

int getShm(int size)
{
    return commShm(size, IPC_CREAT) ; 
}

client.cpp

#include "comm.hpp"

int main()
{
    int shmid  = getShm(1024);
    sleep(1); 
    char* addr = (char*)shmat(shmid, nullptr, 0);
    sleep(1);
    int i = 0 ; 
    while (i < 26)
    {
        addr[i] = 'A' + i ;  // 写入共享内存
        i++ ; 
        addr[i] = 0 ; 
        sleep(1);
    }

    shmdt(addr);
    sleep(2);

    return 0 ; 
}

server.cpp:

#include "comm.hpp"

int main()
{

    int shmid = createShm(1024) ; 
    sleep(1) ; 
    char* addr = (char*)shmat(shmid, nullptr, 0); 
    sleep(2) ;
    int i = 0 ; 
    while (i < 26)
    {
        sleep(1);
        printf("client %s\n", addr);
        i++ ;
    }

    shmdt(addr); 
    sleep(1);
    destroyShm(shmid) ; 
    return 0 ; 
    
}

特别提醒:

  1. 如果写关于使用共享内存进行进程通信代码,测试或使用时,如果没有用代码将创建的共享内存销毁,或是代码还没执行到共享内存销毁的代码就因为其他原因终止,下次启动该程序会失败,因为共享内存没有销毁,且用于生成的共享内存的key不变,执行到shmget()函数的时候就会出错。 解决方法为手动删除该共享内存。
  2. 因为是对内存进行访问,所以写端在写入时,对端关闭也不会造成影响。上述代码读端读取后,如果没有销毁共享内内存,内存中内容任然保留。

补充说明

mkfifo函数

mkfifo函数的原型如下:

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

int mkfifo(const char *pathname, mode_t mode);

功能:创建命名管道。

参数说明:
pathname:要创建的命名管道的路径名。
mode:创建的命名管道的权限,通常使用八进制表示。
mkfifo函数成功创建命名管道时返回0,失败时返回-1,并设置相应的错误码。创建的命名管道可以通过文件I/O函数进行读写操作。

shmdt
功能:将共享内存段与当前进程脱离
原型

 int shmdt(const void *shmaddr);

参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
shmat
功能:将共享内存段连接到进程地址空间
原型

 void *shmat(int shmid, const void *shmaddr, int shmflg);

参数
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

ftok
ftok函数是一个用于生成System V IPC(Inter-Process Communication,进程间通信)中的键值的函数。它的原型如下:

key_t ftok(const char *pathname, int proj_id);

该函数接受一个路径名和一个项目标识符作为参数,并返回一个唯一的键值。这个键值通常用于创建或访问共享内存、消息队列和信号量等System V IPC资源。

ftok函数的工作原理如下:

ftok函数通过将给定的路径名和项目标识符转换为一个32位的键值。
路径名必须指向一个现有的文件。ftok函数使用该文件的inode号和设备号来生成键值。
项目标识符是一个整数,用于区分不同的IPC资源。通常情况下,同一个路径名下的不同项目标识符会生成不同的键值。
需要注意的是,ftok函数在生成键值时可能会受到系统的限制。具体来说,它使用的是32位的键值,因此可能存在键值冲突的情况。如果生成的键值已经被使用,则可能导致创建或访问IPC资源失败。

另外,由于ftok函数使用了文件的inode号和设备号来生成键值,因此如果使用不同的文件系统或文件系统重新挂载,可能会导致生成的键值不同。

shmctl
功能:用于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

在这里插入图片描述

shmid_ds

shmid_ds是System V共享内存的数据结构,用于描述和管理共享内存的属性和状态。它定义在<sys/shm.h>头文件中。

shmid_ds结构体的定义如下:

struct shmid_ds 
{
    struct ipc_perm shm_perm;  // 共享内存的权限信息
    size_t shm_segsz;          // 共享内存的大小(字节)
    time_t shm_atime;          // 上次访问时间
    time_t shm_dtime;          // 上次分离时间
    time_t shm_ctime;          // 上次变更时间
    pid_t shm_cpid;            // 创建共享内存的进程ID
    pid_t shm_lpid;            // 最后一次操作共享内存的进程ID
    unsigned short shm_nattch; // 当前附加到共享内存的进程数
    ...
};

shmid_ds结构体用于在共享内存的创建、访问和管理过程中记录共享内存的相关信息。通过操作shmid_ds结构体的成员,可以获取和修改共享内存的属性,例如权限、大小、创建者等信息。

需要注意的是,shmid_ds结构体中的其他成员没有在上述定义中列出,具体实现可能会有所差异。在使用shmid_ds结构体时,可以参考相关的系统文档和头文件中的定义。

POSIX IPC
POSIX IPC(Portable Operating System Interface Interprocess Communication)是一组跨平台的进程间通信机制,定义在POSIX标准中。它提供了一种可移植的方式来实现进程间的通信和同步。

POSIX IPC包括以下几种机制:

信号量(Semaphore):用于进程间的同步和互斥。通过使用信号量,进程可以等待某个事件的发生或者通知其他进程某个事件已经发生。

消息队列(Message Queue):用于进程间的异步通信。进程可以将消息发送到消息队列中,其他进程可以从队列中接收消息。

共享内存(Shared
Memory):允许多个进程共享同一块内存区域。这种机制可以提高进程间的数据传输效率,但需要进行适当的同步和互斥操作来保证数据的一致性。

互斥锁(Mutex):用于进程间的互斥访问共享资源。通过互斥锁,只有一个进程可以访问共享资源,其他进程需要等待锁的释放才能访问。

POSIX IPC提供了更高级别、更易用的进程间通信机制,相对于System V
IPC而言,它更加灵活、可移植,并且在现代操作系统中得到广泛支持。

System V IPC

System V IPC(进程间通信)是指System V Unix操作系统提供的一组机制,用于进程间通信。它包括三种主要类型的IPC:共享内存、消息队列和信号量。

共享内存允许多个进程访问同一内存段,实现进程间高效的数据共享。消息队列提供了进程发送和接收消息的方式,实现异步通信。信号量用于进程同步和协调,确保多个进程以受控的方式访问共享资源。

System V IPC提供了一种低级别的进程间通信接口,在类Unix操作系统中广泛使用。然而,它已经被较新的IPC机制(如POSIX IPC)所取代,这些机制提供了更好的功能和易用性。

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

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

相关文章

Ubuntu18.04 上通过 jihu 镜像完成 ESP-IDF 编译环境搭建流程

为了解决国内开发者从 github 克隆 esp 相关仓库慢的问题&#xff0c;已将 esp-idf 和部分重要仓库及其关联的子模块镜像到了 jihu&#xff0c;这些仓库将自动从原始仓库进行同步。此篇博客用来阐述 Ubuntu18.04 上通过 jihu 镜像完成 ESP-IDF 编译环境搭建流程。 注&#xff1…

从零开始制作一个Douban图像下载器:Wt库的基础知识和操作指南

引言 欢迎来到本文&#xff0c;如果你希望从豆瓣下载海量的高清图像、学习使用现代C web应用程序框架Wt库开发web应用程序&#xff0c;或者了解如何利用代理IP和多线程技术提高爬虫效率和稳定性&#xff0c;那么你来对地方了。在接下来的内容中&#xff0c;我们将为你提供一个…

Springboot数据加密篇

一、密码加密 1.1Hash算法(MD5/SHA-512等) 哈希算法&#xff0c;又称摘要算法&#xff08;Digest&#xff09;&#xff0c;是一种将任意长度的输入通过散列函数变换成固定长度的输出的单向密码体制。这种映射的规则就是哈希算法&#xff0c;而通过原始数据映射之后得到的二进制…

2023中国品牌节金谱奖荣誉发布 酷开科技获颁OTT行业科技创新奖

11月17日—19日&#xff0c;以“复苏与腾飞”为主题的2023第十七届中国品牌节&#xff0c;在杭州市云栖小镇国际会展中心成功举行。在18日晚间的荣耀盛典上&#xff0c;“TopBrand 2023中国品牌节金谱奖”荣誉发布&#xff0c;酷开科技斩获OTT行业科技创新奖。 酷开科技作为OTT…

JavaWeb笔记之JavaWeb JDBC

//Author 流云 //Version 1.0 一. 引言 1.1 如何操作数据库 使用客户端工具访问数据库&#xff0c;需要手工建立连接&#xff0c;输入用户名和密码登录&#xff0c;编写 SQL 语句&#xff0c;点击执行&#xff0c;查看操作结果&#xff08;结果集或受影响行数&#xff09;。…

MySQL的增删改查(进阶)--上

1. 数据库约束 1.1 约束类型 NOT NULL - 指示某列不能存储 NULL 值。 UNIQUE - 保证某列的每行必须有唯一的值。 DEFAULT - 规定没有给列赋值时的默认值。 PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列&#xff08;或两个列多个列的结合&#xff09;有唯一标识&#xf…

3-10岁孩子数学发展里程碑

文章目录 3岁4岁5岁6-7岁&#xff08;1-2年级&#xff09;8-9岁&#xff08;3-4年级&#xff09;10岁&#xff08;5年级&#xff09; 当然&#xff0c;孩子的数学能力发展会因个体差异而有所不同&#xff0c;但以下是一个大致的指导&#xff0c;用来描述从3岁到10岁孩子在数学上…

HPM6750系列--第十一篇 Uart讲解(轮询模式)

一、目的 在介绍完GPIO的相关内容下一个必须介绍的就是uart了&#xff0c;因为串口一个主要用途就是用于调试信息打印。 HPM6750在uart的配置上也是相当炸裂&#xff0c;有17个串口&#xff1b;结合HPM6750的高主频高内存&#xff0c;完全可以作为一个串口服务器。 ​​​​​​…

Pycharm enable IntelliBot #patched后,工程无法打开

#本地环境# Pycharm&#xff1a;2023.12 Pro 对应robot pkg版本&#xff1a; robotframework 6.1 robotframework-databaselibrary 1.2.4 robotframework-pythonlibcore 4.1.2 robotframework-requests 0.9.4 robotframework-seleniumlibrary 6.1.…

新增工具箱管理功能、重构网站证书管理功能,1Panel开源面板v1.9.0发布

2023年12月18日&#xff0c;现代化、开源的Linux服务器运维管理面板1Panel正式发布v1.9.0版本。 在这一版本中&#xff0c;1Panel引入了新的工具箱管理功能&#xff0c;包含Swap分区管理、Fail2Ban管理等功能。此外&#xff0c;1Panel针对网站证书管理功能进行了全面重构&…

移动云捐赠三款开源项目,加速新一代基础软件生态繁荣

随着云计算、大数据、人工智能等新领域新信息技术的发展&#xff0c;我国基础软件的自主可控极大程度地影响着产业链上下游的多样性和技术创新的发展空间。移动云作为中国移动涉云业务的主入口&#xff0c;一直坚持共享开源价值&#xff0c;积极推动中国开源软件生态的繁荣发展…

UE5 水材质注意要点

1、两个法线反向交替流动&#xff0c;可以去观感假的现象 2、水面延边的透明度低 3、增加水面延边的浪花 4、增加折射 折射要整体质量至少在High才有效果 改为半透明材质没有法线信息&#xff1f; 5、处理反射效果 勾选为true 找到这个放在水域 勾为false&#xff0c;即可有非…

基于ssm品牌手机销售信息系统论文

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于品牌手机销售信息系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了品牌手机销售信息系统&#xff0c;它彻底…

05_Web框架之Django二

Web框架之Django二 学习目标和内容 1、能够使用类视图的写法 2、能够使用模板语言的相关语法 3、能够理解过滤器的作用 4、能够理解并使用模板继承 一、类视图 1、类视图介绍 视图是一个可调用的对象&#xff0c;它接收一个请求然后返回一个响应&#xff0c;这个可调用对象可…

phpmyadmin4.8.1远程文件包含漏洞 [GWCTF 2019]我有一个数据库1

打开题目 我们用dirsearch扫描一下后台看看 扫描结果如下 我们访问一下robots.txt看看&#xff0c;提示有phpinfo.php 那我们访问一下phpinfo.php 发现没有任何信息后我们转去看看phpmyadmin看看 成功访问到页面 在这里我们看到phpmyadmin的版本号是4.8.1 我们百度搜索一下看…

Java版企业电子招投标系统源代码,支持二次开发,采用Spring cloud微服务架构

招投标管理系统是一个集门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理于一体的综合性应用平台。它适用于招标代理、政府采购、企业采购和工程交易等业务的企业&#xff0c;旨在提高项目管理的效率和质量。该系…

linux搭建gitlab

gitlab的介绍 区别于github&#xff0c;github是面向互联网基于git实现的代码托管平台&#xff0c;gitlab是基于Ruby语言实现的git管理平台软件&#xff0c;一般用于公司内部代码仓库。 gitlab组成 Nginx 静态Web服务器Gitlab-workhorse 轻量级的反向代理服务器Gitlab-shell 用…

spring MVC概述和土门案例(无配置文件开发)

SpringMVC 1&#xff0c;SpringMVC概述2&#xff0c;SpringMVC入门案例2.1 需求分析2.2 案例制作步骤1:创建Maven项目步骤2:补全目录结构步骤3:导入jar包步骤4:创建配置类步骤5:创建Controller类步骤6:使用配置类替换web.xml步骤7:配置Tomcat环境步骤8:启动运行项目步骤9:浏览器…

Android 大版本升级变更截图方法总结

Android 大版本升级变更截图方法总结 一、Android R (11) 平台二、Android S (12) 平台三、Android U (14) 平台 Android 原生的截屏功能是集成在 SystemUI 中&#xff0c;因此我们普通应用想要获取截图方法&#xff0c;就需要研读下 SystemUI 截屏部分的功能实现。 一、Androi…

RocketMQ系统性学习-SpringCloud Alibaba集成RocketMQ以及消费收发实战

文章目录 Spring Cloud Alibaba 集成 RocketMQ 最佳实践集成依赖DashBoard消息收发实战 Spring Cloud Alibaba 集成 RocketMQ 最佳实践 SpringBoot 相对于 SSM 来说已经很大程度上简化了开发&#xff0c;但是使用 SpringBoot 集成一些第三方的框架&#xff0c;还是需要花费一些…