【Linux】Linux进程间通信(二)

news2024/11/28 14:31:28

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:Linux
🎯长路漫漫浩浩,万事皆有期待

上一篇博客:【Linux】Linux进程间通信(一)

文章目录

    • 命名管道
      • 命名管道的原理
      • 创建一个命名管道
      • 命名管道的打开规则
      • 用命名管道实现serve&client通信
      • 用命名管道实现派发计算任务
      • 用命名管道实现进程遥控
      • 用命名管道实现文件拷贝
      • 命名管道和匿名管道的区别
  • 总结:

命名管道

命名管道的原理

匿名管道只能用于具有共同祖先的进程(具有亲缘关系的进程)之间的通信,通常,一个管道由一个进程创建,然后该进程调用fork,此后父子进程之间就可应用该管道。
如果要实现两个毫不相关进程之间的通信,可以使用命名管道来做到。命名管道就是一种特殊类型的文件,两个进程通过命名管道的文件名打开同一个管道文件,此时这两个进程也就看到了同一份资源,进而就可以进行通信了。

注意:

普通文件是很难做到通信的,即便做到通信也无法解决一些安全问题。
命名管道和匿名管道一样,都是内存文件,只不过命名管道在磁盘有一个简单的映像,但这个映像的大小永远为0,因为命名管道和匿名管道都不会将通信数据刷新到磁盘当中。
使用命令创建命名管道
我们可以使用mkfifo命令创建一个命名管道。

mkfifo fifo

在这里插入图片描述

可以看到,创建出来的文件的类型是p,代表该文件是命名管道文件。
在这里插入图片描述

使用这个命名管道文件,就能实现两个进程之间的通信了。我们在一个进程(进程A)中用shell脚本每秒向命名管道写入一个字符串,在另一个进程(进程B)当中用cat命令从命名管道当中进行读取。
现象就是当进程A启动后,进程B会每秒从命名管道中读取一个字符串打印到显示器上。这就证明了这两个毫不相关的进程可以通过命名管道进行数据传输,即通信。
在这里插入图片描述

之前我们说过,当管道的读端进程退出后,写端进程再向管道写入数据就没有意义了,此时写端进程会被操作系统杀掉,在这里就可以很好的得到验证:当我们终止掉读端进程后,因为写端执行的循环脚本是由命令行解释器bash执行的,所以此时bash就会被操作系统杀掉,我们的云服务器也就退出了。

创建一个命名管道

在程序中创建命名管道使用mkfifo函数,mkfifo函数的函数原型如下:

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

mkfifo函数的第一个参数是pathname,表示要创建的命名管道文件。

若pathname以路径的方式给出,则将命名管道文件创建在pathname路径下。
若pathname以文件名的方式给出,则将命名管道文件默认创建在当前路径下。(注意当前路径的含义)

mkfifo函数的第二个参数是mode,表示创建命名管道文件的默认权限。

例如,将mode设置为0666,则命名管道文件创建出来的权限如下:

prw-rw-rw-

但实际上创建出来文件的权限值还会受到umask(文件默认掩码)的影响,实际创建出来文件的权限为:mode&(~umask)。umask的默认值一般为0002,当我们设置mode值为0666时实际创建出来文件的权限为0664。

prw-rw-r--

若想创建出来命名管道文件的权限值不受umask的影响,则需要在创建文件前使用umask函数将文件默认掩码设置为0。

umask(0); //将文件默认掩码设置为0

mkfifo函数的返回值。

命名管道创建成功,返回0。
命名管道创建失败,返回-1。

创建命名管道示例:

使用以下代码即可在当前路径下,创建出一个名为myfifo的命名管道。

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

#define FILE_NAME "myfifo"

int main()
{
	umask(0); //将文件默认掩码设置为0
	if (mkfifo(FILE_NAME, 0666) < 0){ //使用mkfifo创建命名管道文件
		perror("mkfifo");
		return 1;
	}

	//create success...

	return 0;
}

运行代码后,命名管道myfifo就在当前路径下被创建了。
在这里插入图片描述

命名管道的打开规则

1、如果当前打开操作是为读而打开FIFO时。

O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO。
O_NONBLOCK enable:立刻返回成功。

2、如果当前打开操作是为写而打开FIFO时。

O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO。
O_NONBLOCK enable:立刻返回失败,错误码为ENXIO。

用命名管道实现serve&client通信

实现服务端(server)和客户端(client)之间的通信之前,我们需要先让服务端运行起来,我们需要让服务端运行后创建一个命名管道文件,然后再以读的方式打开该命名管道文件,之后服务端就可以从该命名管道当中读取客户端发来的通信信息了。

服务端的代码如下:

//server.c
#include "comm.h"

int main()
{
	umask(0); //将文件默认掩码设置为0
	if (mkfifo(FILE_NAME, 0666) < 0){ //使用mkfifo创建命名管道文件
		perror("mkfifo");
		return 1;
	}
	int fd = open(FILE_NAME, O_RDONLY); //以读的方式打开命名管道文件
	if (fd < 0){
		perror("open");
		return 2;
	}
	char msg[128];
	while (1){
		msg[0] = '\0'; //每次读之前将msg清空
		//从命名管道当中读取信息
		ssize_t s = read(fd, msg, sizeof(msg)-1);
		if (s > 0){
			msg[s] = '\0'; //手动设置'\0',便于输出
			printf("client# %s\n", msg); //输出客户端发来的信息
		}
		else if (s == 0){
			printf("client quit!\n");
			break;
		}
		else{
			printf("read error!\n");
			break;
		}
	}
	close(fd); //通信完毕,关闭命名管道文件
	return 0;
}

而对于客户端来说,因为服务端运行起来后命名管道文件就已经被创建了,所以客户端只需以写的方式打开该命名管道文件,之后客户端就可以将通信信息写入到命名管道文件当中,进而实现和服务端的通信。

客户端的代码如下:

//client.c
#include "comm.h"

int main()
{
	int fd = open(FILE_NAME, O_WRONLY); //以写的方式打开命名管道文件
	if (fd < 0){
		perror("open");
		return 1;
	}
	char msg[128];
	while (1){
		msg[0] = '\0'; //每次读之前将msg清空
		printf("Please Enter# "); //提示客户端输入
		fflush(stdout);
		//从客户端的标准输入流读取信息
		ssize_t s = read(0, msg, sizeof(msg)-1);
		if (s > 0){
			msg[s - 1] = '\0';
			//将信息写入命名管道
			write(fd, msg, strlen(msg));
		}
	}
	close(fd); //通信完毕,关闭命名管道文件
	return 0;
}

对于如何让客户端和服务端使用同一个命名管道文件,这里我们可以让客户端和服务端包含同一个头文件,该头文件当中提供这个共用的命名管道文件的文件名,这样客户端和服务端就可以通过这个文件名,打开同一个命名管道文件,进而进行通信了。

共用头文件的代码如下:

//comm.h
#pragma once

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

#define FILE_NAME "myfifo" //让客户端和服务端使用同一个命名管道

代码编写完毕后,先将服务端进程运行起来,之后我们就能在客户端看到这个已经被创建的命名管道文件。
在这里插入图片描述

接着再将客户端也运行起来,此时我们从客户端写入的信息被客户端写入到命名管道当中,服务端再从命名管道当中将信息读取出来打印在服务端的显示器上,该现象说明服务端是能够通过命名管道获取到客户端发来的信息的,换句话说,此时这两个进程之间是能够通信的。
在这里插入图片描述

当客户端和服务端运行起来时,我们还可以通过ps命令查看这两个进程的信息,可以发现这两个进程确实是两个毫不相关的进程,因为它们的PID和PPID都不相同。也就证明了,命名管道是可以实现两个毫不相关进程之间的通信的。
在这里插入图片描述

服务端和客户端之间的退出关系

当客户端退出后,服务端将管道当中的数据读完后就再也读不到数据了,那么此时服务端也就会去执行它的其他代码了(在当前代码中是直接退出了)。
在这里插入图片描述

当服务端退出后,客户端写入管道的数据就不会被读取了,也就没有意义了,那么当客户端下一次再向管道写入数据时,就会收到操作系统发来的13号信号(SIGPIPE),此时客户端就被操作系统强制杀掉了。
在这里插入图片描述

通信是在内存当中进行的

若是我们只让客户端向管道写入数据,而服务端不从管道读取数据,那么这个管道文件的大小会不会发生变化呢?

//server.c
#include "comm.h"

int main()
{
	umask(0); //将文件默认掩码设置为0
	if (mkfifo(FILE_NAME, 0666) < 0){ //使用mkfifo创建命名管道文件
		perror("mkfifo");
		return 1;
	}
	int fd = open(FILE_NAME, O_RDONLY); //以读的方式打开命名管道文件
	if (fd < 0){
		perror("open");
		return 2;
	}
	while (1){
		//服务端不读取管道信息
	}
	close(fd); //通信完毕,关闭命名管道文件
	return 0;
}

可以看到,尽管服务端不读取管道当中的数据,但是管道当中的数据并没有被刷新到磁盘,使用ll命令看到命名管道文件的大小依旧为0,也就说明了双方进程之间的通信依旧是在内存当中进行的,和匿名管道通信是一样的。
在这里插入图片描述

用命名管道实现派发计算任务

需要注意的是两个进程之间的通信,并不是简单的发送字符串而已,服务端是会对客户端发送过来的信息进行某些处理的。

这里我们以客户端向服务端派发计算任务为例,客户端通过管道向服务端发送双操作数的计算请求,服务端接收到客户端的信息后需要计算出相应的结果。

这里我们无需更改客户端的代码,只需改变服务端处理通信信息的逻辑即可。

//server.c
#include "comm.h"

int main()
{
	umask(0); //将文件默认掩码设置为0
	if (mkfifo(FILE_NAME, 0666) < 0){ //使用mkfifo创建命名管道文件
		perror("mkfifo");
		return 1;
	}
	int fd = open(FILE_NAME, O_RDONLY); //打开命名管道文件
	if (fd < 0){
		perror("open");
		return 2;
	}
	char msg[128];
	while (1){
		msg[0] = '\0'; //每次读之前将msg清空
		//从命名管道当中读取信息
		ssize_t s = read(fd, msg, sizeof(msg)-1);
		if (s > 0){
			msg[s] = '\0'; //手动设置'\0',便于输出
			printf("client# %s\n", msg);
			//服务端进行计算任务
		    char* lable = "+-*/%";
			char* p = msg;
			int flag = 0;
			while (*p){
				switch (*p){
				case '+':
					flag = 0;
					break;
				case '-':
					flag = 1;
					break;
				case '*':
					flag = 2;
					break;
				case '/':
					flag = 3;
					break;
				case '%':
					flag = 4;
					break;
				}
				p++;
			}
			char* data1 = strtok(msg, "+-*/%");
			char* data2 = strtok(NULL, "+-*/%");
			int num1 = atoi(data1);
			int num2 = atoi(data2);
			int ret = 0;
			switch (flag){
			case 0:
				ret = num1 + num2;
				break;
			case 1:
				ret = num1 - num2;
				break;
			case 2:
				ret = num1 * num2;
				break;
			case 3:
				ret = num1 / num2;
				break;
			case 4:
				ret = num1 % num2;
				break;
			}
			printf("%d %c %d = %d\n", num1, lable[flag], num2, ret); //打印计算结果
		}
		else if (s == 0){
			printf("client quit!\n");
			break;
		}
		else{
			printf("read error!\n");
			break;
		}
	}
	close(fd); //通信完毕,关闭命名管道文件
	return 0;
}

此时服务端接收到客户端的信息后,需要进行的处理动作就不是将其打印到显示器了,而是需要将信息经过进一步的处理,从而得到相应的结果。
在这里插入图片描述

用命名管道实现进程遥控

比较有意思的是,我们可以通过一个进程来控制另一个进程的行为,比如我们从客户端输入命令到管道当中,再让服务端将管道当中的命令读取出来并执行。

下面我们只实现了让服务端执行不带选项的命令,若是想让服务端执行带选项的命令,可以对管道当中获取的命令进行解析处理。这里的实现非常简单,只需让服务端从管道当中读取命令后创建子进程,然后再进行进程程序替换即可。

这里也无需更改客户端的代码,只需改变服务端处理通信信息的逻辑即可。

#include "comm.h"

int main()
{
	umask(0); //将文件默认掩码设置为0
	if (mkfifo(FILE_NAME, 0666) < 0){ //使用mkfifo创建命名管道文件
		perror("mkfifo");
		return 1;
	}
	int fd = open(FILE_NAME, O_RDONLY); //以读的方式打开命名管道文件
	if (fd < 0){
		perror("open");
		return 2;
	}
	char msg[128];
	while (1){
		msg[0] = '\0'; //每次读之前将msg清空
		//从命名管道当中读取信息
		ssize_t s = read(fd, msg, sizeof(msg)-1);
		if (s > 0){
			msg[s] = '\0'; //手动设置'\0',便于输出
			printf("client# %s\n", msg);
			if (fork() == 0){
				//child
				execlp(msg, msg, NULL); //进程程序替换
				exit(1);
			}
			waitpid(-1, NULL, 0); //等待子进程
		}
		else if (s == 0){
			printf("client quit!\n");
			break;
		}
		else{
			printf("read error!\n");
			break;
		}
	}
	close(fd); //通信完毕,关闭命名管道文件
	return 0;
}

此时服务端接收到客户端的信息后,便进行进程程序替换,进而执行客户端发送过来的命令。
在这里插入图片描述

用命名管道实现文件拷贝

这里我们再用命名管道实现一下文件的拷贝。

需要拷贝的文件是file.txt,该文件当中的内容如下:
在这里插入图片描述

我们要做的就是,让客户端将file.txt文件通过管道发送给服务端,在服务端创建一个file-bat.txt文件,并将从管道获取到的数据写入file-bat.txt文件当中,至此便实现了file.txt文件的拷贝。

其中服务端需要做的就是,创建命名管道并以读的方式打开该命名管道,再创建一个名为file-bat.txt的文件,之后需要做的就是将从管道当中读取到的数据写入到file-bat.txt文件当中即可。

服务端的代码如下:

//server.c
#include "comm.h"

int main()
{
	umask(0); //将文件默认掩码设置为0
	if (mkfifo(FILE_NAME, 0666) < 0){ //使用mkfifo创建命名管道文件
		perror("mkfifo");
		return 1;
	}
	int fd = open(FILE_NAME, O_RDONLY); //以读的方式打开命名管道文件
	if (fd < 0){
		perror("open");
		return 2;
	}
	//创建文件file-bat.txt,并以写的方式打开该文件
	int fdout = open("file-bat.txt", O_CREAT | O_WRONLY, 0666);
	if (fdout < 0){
		perror("open");
		return 3;
	}
	char msg[128];
	while (1){
		msg[0] = '\0'; //每次读之前将msg清空
		//从命名管道当中读取信息
		ssize_t s = read(fd, msg, sizeof(msg)-1);
		if (s > 0){
			write(fdout, msg, s); //将读取到的信息写入到file-bat.txt文件当中
		}
		else if (s == 0){
			printf("client quit!\n");
			break;
		}
		else{
			printf("read error!\n");
			break;
		}
	}
	close(fd); //通信完毕,关闭命名管道文件
	close(fdout); //数据写入完毕,关闭file-bat.txt文件
	return 0;
}

而客户端需要做的就是,以写的方式打开这个已经存在的命名管道文件,再以读的方式打开file.txt文件,之后需要做的就是将file.txt文件当中的数据读取出来并写入管道当中即可。

客户端的代码如下:

//client.c
#include "comm.h"

int main()
{
	int fd = open(FILE_NAME, O_WRONLY); //以写的方式打开命名管道文件
	if (fd < 0){
		perror("open");
		return 1;
	}
	int fdin = open("file.txt", O_RDONLY); //以读的方式打开file.txt文件
	if (fdin < 0){
		perror("open");
		return 2;
	}
	char msg[128];
	while (1){
		//从file.txt文件当中读取数据
		ssize_t s = read(fdin, msg, sizeof(msg));
		if (s > 0){
			write(fd, msg, s); //将读取到的数据写入到命名管道当中
		}
		else if (s == 0){
			printf("read end of file!\n");
			 break;
		}
		else{
			printf("read error!\n");
			break;
		}
	}
	close(fd); //通信完毕,关闭命名管道文件
	close(fdin); //数据读取完毕,关闭file.txt文件
	return 0;
}

共用头文件的代码和之前的一样,如下:

//comm.h
#pragma once

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

#define FILE_NAME "myfifo" //让客户端和服务端使用同一个命名管道

编写完代码后,先运行服务端,再运行客户端,一瞬间这两个进程就相继运行结束了。
在这里插入图片描述

此时使用ll命令就可以看到,已经完成了file.txt文件的拷贝。
在这里插入图片描述

使用cat命令打印file-bat.txt文件当中的内容,发现和file.txt文件当中的内容相同,拷贝文件成功。
在这里插入图片描述

使用管道实现文件的拷贝有什么意义?

因为这里是使用管道在本地进行的文件拷贝,所以看似没什么意义,但我们若是将这里的管道想象成“网络”,将客户端想象成“Windows Xshell”,再将服务端想象成“centos服务器”。那我们此时实现的就是文件上传的功能,若是将方向反过来,那么实现的就是文件下载的功能。
在这里插入图片描述

命名管道和匿名管道的区别

匿名管道由pipe函数创建并打开。
命名管道由mkfifo函数创建,由open函数打开。
FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在于它们创建与打开的方式不同,一旦这些工作完成之后,它们具有相同的语义。

命令行当中的管道
现有data.txt文件,文件当中的内容如下:
在这里插入图片描述

我们可以利用管道(“|”)同时使用cat命令和grep命令,进而实现文本过滤。

cat data.txt | grep sherry

在这里插入图片描述

那么在命令行当中的管道(“|”)到底是匿名管道还是命名管道呢?

由于匿名管道只能用于有亲缘关系的进程之间的通信,而命名管道可以用于两个毫不相关的进程之间的通信,因此我们可以先看看命令行当中用管道(“|”)连接起来的各个进程之间是否具有亲缘关系。

下面通过管道(“|”)连接了三个进程,通过ps命令查看这三个进程可以发现,这三个进程的PPID是相同的,也就是说它们是由同一个父进程创建的子进程。
在这里插入图片描述

而它们的父进程实际上就是命令行解释器,这里为bash。
在这里插入图片描述

也就是说,由管道(“|”)连接起来的各个进程是有亲缘关系的,它们之间互为兄弟进程。
在这里插入图片描述
现在我们已经知道了,若是两个进程之间采用的是命名管道,那么在磁盘上必须有一个对应的命名管道文件名,而实际上我们在使用命令的时候并不存在类似的命名管道文件名,因此命令行上的管道实际上是匿名管道。

总结:

今天我们学习了Linux进程间通信的相关知识,了解了进程间通信介绍,管道等 。接下来,我们将继续学习Linux的其他知识。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

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

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

相关文章

【开源】基于Vue和SpringBoot的固始鹅块销售系统

项目编号&#xff1a; S 060 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S060&#xff0c;文末获取源码。} 项目编号&#xff1a;S060&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固…

Elasticsearch:运用向量搜索通过图像搜索找到你的小狗

作者&#xff1a;ALEX SALGADO 你是否曾经遇到过这样的情况&#xff1a;你在街上发现了一只丢失的小狗&#xff0c;但不知道它是否有主人&#xff1f; 了解如何使用向量搜索或图像搜索来做到这一点。 通过图像搜索找到你的小狗 您是否曾经遇到过这样的情况&#xff1a;你在街…

【自留地】前端 - uniapp - Vue - React - Flutter

uniapp uniapp自用速查表 - 我的常用组件 uniapp自用速查表 - 我的常用组件_uniapp static/customicons.css-CSDN博客文章浏览阅读1.8k次。uniapp项目登录退出、全局变量与状态、本地存储、Tabbar标签栏、顶部导航栏、下拉刷新、触底刷新、Ajax交互、内置组件样式修改、自定义…

2018年五一杯数学建模C题江苏省本科教育质量综合评价解题全过程文档及程序

2019年五一杯数学建模 C题 江苏省本科教育质量综合评价 原题再现 随着中国的改革开放&#xff0c;国家的综合实力不断增强&#xff0c;中国高等教育发展整体已进入世界中上水平。作为一个教育大省&#xff0c;江苏省的本科教育发展在全国名列前茅&#xff0c;而江苏省13个地级…

Linux:进程替换和知识整合

文章目录 进程程序替换替换原理进程替换的理解 环境变量与进程替换命令行解释器实现逻辑 进程程序替换 前面已经学习了子进程的创建&#xff0c;但是子进程的创建不管怎么说&#xff0c;都是父进程代码的一部分&#xff0c;那么实际上如果想要子进程执行新的程序呢&#xff1f…

2023年中国脑电仿生电刺激仪发展趋势分析:智能化、精准化、使用感不断提高[图]

脑电仿生电刺激仪是一种通过直接数字频率合成技术合成脑电仿真低频生物电流&#xff0c;通过粘贴于两耳侧乳突、太阳穴或风池穴部位表皮的电极&#xff0c;用仿生物电自颅外无创伤地穿透颅骨屏障刺激小脑顶核区的电疗设备。此电流刺激可启动颅脑固有神经保护机制&#xff0c;改…

【MATLAB】史上最全的9种数据拟合算法全家桶

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 大家吃一顿火锅的价格便可以拥有9种数据拟合算法&#xff0c;绝对不亏&#xff0c;知识付费是现今时代的趋势&#xff0c;而且都是我精心制作的教程&#xff0c;有问题可随时反馈~也可单独获取某一算法的代码&#xff08…

Odoo 15开发手册第六章 模型 - 结构化应用数据

本章我们更进一步学习模型层&#xff0c;以及如何使用模型来设计支撑应用的数据结构。我们会探讨可用的模型类型&#xff0c;以及在使用这些类型时如何定义强制进行数据验证的约束。 模型由支持不同数据类型的数据字段组成&#xff0c;一些字段类型支持定义模型间的关联。对于…

delphi电子处方流转 sm2 sm4(医院)

【delphi电子处方流转(医院) sm2 sm4】支持 就诊登记、电子处方上传预核验、处方处方医保电子签名、电子处方上传、电子处方撤销、电子处方信息查询、电子处方审核结果查询、电子处方取药结果查询、电子处方药品目录查询等功能。技术交流Q 648437169 下载链接&#xff1a;http…

4. hdfs高可用集群搭建

简介 前面把hadoop机器已经准备好了&#xff0c;zk集群搭建好了&#xff0c;本本就是开始搭建hdfs环境 hadoop环境准备 创建hadoop用户 三台机器都创建hadoop用户 useradd hadoop -d /home/hadoop echo "1q1w1e1r" | passwd --stdin hadoophadoop用户相互免密登…

语义检索系统【全】:基于milvus语义检索系统指令全流程-快速部署版

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

Linux操作系统基础 – 正则表达式快速入门

Linux操作系统基础 – 正则表达式快速入门 Linux Operating System Essentials - Introduction to Regular Expressions 通常在计算机科学领域&#xff0c;正则表达式被解释为对字符串操作的一种逻辑公式&#xff0c;即用事先定义好的特定字符及其组合组成所谓的“规则字符串”…

SpringBoot使用DevTools实现后端热部署

&#x1f4d1;前言 本文主要SpringBoot通过DevTools实现热部署的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&…

GZ038 物联网应用开发赛题第10套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 &#xff08;第10套卷&#xff09; 工位号&#xff1a;______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具&#xff0c;操作安全规范&#xff1b; 2、竞赛过程中如有异议&#xff0c;可向现场考…

ai剪辑矩阵系统源码+无人直播系统源码技术开发

开发AI剪辑矩阵系统和无人直播系统源码&#xff0c;需要以下步骤&#xff1a; 1. 市场调研&#xff1a;了解市场需求和竞品情况&#xff0c;明确系统的功能和特点。 2. 系统设计&#xff1a;设计系统的整体架构和功能模块&#xff0c;包括视频剪辑、直播推流、实时互动、数据分…

【Linux】Ubuntu16.04下安装python高版本--源码安装

Ubuntu16.04下完美安装python高版本及对应版本的pip 方法一:直接用命令安装python3.6&#xff08;但我没安装成功&#xff09; 好像是因为Ubuntu16.04的软件仓库&#xff08;源&#xff09;中python的最高版本就是python3.5&#xff0c;所以无法直接用apt来安装 #方法一 sudo…

学习c#的第十四天

目录 C# 接口&#xff08;Interface&#xff09; 接口的特点 定义接口 接口继承 接口和抽象类的区别 C# 命名空间&#xff08;Namespace&#xff09; using 关键字 定义命名空间 嵌套命名空间 C# 接口&#xff08;Interface&#xff09; 接口定义了所有类继承接口时应…

Linux系统进程——进程的退出、子进程退出的收集、孤儿进程

进程退出 进程退出主要分为两种&#xff1a;正常退出、异常退出 正常退出 正常退出分为以下几种&#xff1a; 1.main函数调用return 2.进程调用exit(),标准c库 3.进程调用 _exit() 或者 _Exit() &#xff0c;属于系统调用 4.进程最后一个线程返回 5.最后一个线程调用pthrea…

asp.net网上书店管理系统VS开发sqlserver数据库web结构c#编程计算机网页源码项目

一、源码特点 asp.net网上书店管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 asp.net网上书店系统1 二、功能介绍 本系统使用Microsoft Visual Studio 2019为开发工具&#xff0c;SQL Server为…

影响气膜建筑坍塌的原因

气膜建筑以其轻盈、透光、环保等特性&#xff0c;逐渐在建筑领域崭露头角。然而&#xff0c;这种建筑形式并非没有缺陷&#xff0c;其安全性与稳定性直接影响到建筑物的使用寿命和人员安全。 一、结构设计不合理 气膜建筑的结构设计是影响其稳定性的关键因素。良好的结构设计能…