【Linux】进程间通信2——命名管道
1. 命名管道(FIFO)
1.1. 基本概念
简单,给匿名管道起个名字就变成了命名管道
那么如何给 匿名管道 起名字呢?
- 结合文件系统,给匿名管道这个纯纯的内存文件分配 inode,将文件名与之构建联系,关键点在于不给它分配 Data block,因为它是一个纯纯的内存文件,是不需要将数据刷盘到磁盘中的
可以将命名管道理解为 “挂名” 后的匿名管道,把匿名管道加入文件系统中,但仅仅是挂个名而已,目的就是为了让其他进程也能看到这个文件(文件系统中的文件可以被所有进程看到)
因为没有 Data block,所以命名管道这个特殊文件大小为 0
匿名管道只能用于具有共同祖先的进程(具有亲缘关系的进程)之间的通信,如果要实现两个毫不相关进程之间的通信,可以使用命名管道来做到。
普通文件是很难做到通信的,即便做到通信也无法解决一些安全问题。
命名管道和匿名管道一样,都是内存文件,只不过命名管道在磁盘有一个简单的映像,但这个映像的大小永远为0,因为命名管道和匿名管道都不会将通信数据刷新到磁盘当中。
不同于匿名管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。
- 命名管道是一个文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。
- 值得注意的是,FIFO(first input first output)总是按照先进先出的原则工作,第一个被写⼊的数据将首先从管道中读出。
匿名管道是在进程中由pipe()系统调用创建的管道文件. 对用户来说其实是不可见的. 也不能被其他毫无干系的进程打开. 只能通过pipe创建、打开
而命名管道则不同,
命名管道对用户来说, 是可见的, 也就是说在进程内是可以指定路径打开的, 这也是 命名管道可以实现 毫不相干的进程之间通信的原因

1.2.毫不相干的进程之间是怎么通信的
命名管道就是一种特殊类型的文件,两个进程通过命名管道的文件名打开同一个管道文件,此时这两个进程也就看到了同一份资源,进而就可以进行通信了。
虽然命名管道看起来很像文件,但是本质上这个文件也是一个内存文件,只不过在内存上只有一个简单的映像,永远都是 0 ,就只占了一个名字罢了。两个进程只需要通过这个名字在内存中打开文件就好了。
我们来验证一下
我要完成的目的是在用户端 client 输入数据(从屏幕中读取去),而在客户端 server 接收客户端的数据,然后再从客户端打印出来。
但是这里需要注意的是,我们要想进行通信,那么就必须可以看到同一份资源,所以这里我就将共同的资源放到了头文件里,然后两个程序就可以看到同一份资源了:
comm.h1 #pragma once2 #include <stdio.h>3 #include <unistd.h>4 #include <string.h>5 #include <sys/types.h>6 #include <sys/stat.h> 7 #include <fcntl.h>8 9 #define FILE_NAME "myfifo"
server.c1 #include"comm.h"2 3 int main()4 {5 if(mkfifo(FILE_NAME, 0644) < 0){6 perror("myfifo");7 return 1;8 }9 10 int fd = open(FILE_NAME, O_RDONLY);11 if(fd < 0){12 perror("open");13 return 2;14 }15 16 char msg[128];17 while(1){18 msg[0] = 0;19 ssize_t s = read(fd, msg, sizeof(msg)- 1);20 if(s > 0){21 msg[s] = 0;22 printf("client# %s\n", msg);23 }24 else if(s == 0){25 printf("client quit!\n");26 break;27 }28 else{29 printf("read error!\n");30 break; 31 }32 }33 close(fd);34 35 return 0;36 }
client.c1 #include"comm.h"2 3 int main()4 {5 int fd = open(FILE_NAME, O_WRONLY);6 if(fd < 0){7 perror("open");8 return 1; 9 } 10 11 char msg[128]; 12 while(1){ 13 msg[0] = 0; 14 printf("Please Enter# ");15 fflush(stdout); 16 ssize_t s = read(0, msg, sizeof(msg));17 if(s > 0){18 msg[s] = 0; 19 write(fd, msg, strlen(msg)); 20 } 21 } 22 23 close(fd); 24 return 0;25 }

我们可以看到这样的效果。

而且我们会发现,这两个进程是没有任何关系的,但是它们两个就可以进行通信。而且除了 server 创建一个管道文件,其它的操作和操作普通文件没有区别。
那么接下来就操作:情况是不是在命名管道开头的那幅图的情况:
首先先把 server 中读取的操作去掉:

然后进行下方操作:

我们可以看到,我已经写了好多消息了,但是我们发现 myfifo 的大小一直都是 0 ,换句话说就是我写的消息已经被写到管道的缓冲区里了,但是 server端 并没有读取,所以写的消息还是在内存里,但是又因为 myfifo 的大小为 0 ,就说明数据并没有刷新到磁盘,也就意味着,双方通信依旧是在内存中通信的,和匿名管道的底层原理是一样的,它们采用的都是文件通信。
所以这下也就更能理解上面的那副图了吧。
1.3.命名管道的工作原理
1.4、命名管道与匿名管道的区别
不同点:
- 匿名管道只能用于具有血缘关系的进程间通信;而命名管道不讲究,谁都可以用
- 匿名管道直接通过 pipe 函数创建使用;而命名管道需要先通过 mkfifo 函数创建,然后再通过 open 打开使用
- 出现多条匿名管道时,可能会出现写端 fd 重复继承的情况;而命名管道不会出现这种情况
在其他方面,匿名管道与命名管道几乎一致
两个都属于管道家族,都是最古老的进程间通信方式,都自带同步与互斥机制,提供的都是流式数据传输
2.创建命名管道
2.1.mkfifo命令
我们可以使用mkfifo命令来创建命名管道

mkfifo 命名管道的名字
成功解锁了一种新的特殊类型文件:
p管道文件
这个管道文件也非常特殊:大小为 0,从侧面说明 管道文件就是一个纯纯的内存级文件,有自己的上限,出现在文件系统中,只是单纯挂个名而已
2.2.mkfifo函数
此外我们还可以通过相关的函数来创建,这个函数也叫mkfifo
![]()


#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *path,mode_t mode);path为创建的命名管道的全路径名:
mod为指定了文件的读写权限; 成功都返回0,失败都返回-1
参数 : mkfifo函数的第一个参数是pathname,表示要创建的命名管道文件。
- 若pathname以路径的方式给出,则将命名管道文件创建在pathname路径下。
- 若pathname以文件名的方式给出,则将命名管道文件默认创建在当前路径下。(注意当前路径的含义)
mkfifo函数的第二个参数是mode,表示创建命名管道文件的默认权限。
返回值: 命名管道创建成功,返回0 ; 命名管道创建失败,返回-1。
3.命名管道的使用
命名管道和管道的使用方法法基本是相同的。
只是使用命名管道时,必须先调用open()将其打开。因为命名管道是一个存在于硬盘上的文件,而管道是存在于内存中的特殊文件。
需要注意的是,调用open()打开命名管道的进程可能会被阻塞。
- 但如果同时用读写方式( O_RDWR)打开,则一定不会导致阻塞;
- 如果以只读方式( O_RDONLY)打开,则调用open()函数的进程将会被阻塞直到有写方打开管道;
- 同样以写方式( O_WRONLY)打开也会阻塞直到有读方式打开管道。
①如果当前打开操作是为读而打开FIFO时。
- O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO。
- O_NONBLOCK enable:立刻返回成功。
②如果当前打开操作是为写而打开FIFO时。
- O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO。
- O_NONBLOCK enable:立刻返回失败,错误码为ENXIO。
4.命名管道的四个使用示例
(1)通过命名管道 ,client & server进行通信
①comm.h中包含一些头文件供client 和 server使用
//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" //让客户端和服务端使用同一个命名管道
②server.c 代码
实现服务端(server)和客户端(client)之间的通信之前,我们需要先让服务端运行起来,我们需要让服务端运行后创建一个命名管道文件,然后再以读的方式打开该命名管道文件,之后服务端就可以从该命名管道当中读取客户端发来的通信信息了。
#include "comm.h"int main()
{if(mkfifo(FILE_NAME , 0644) < 0){ //创建管道文件perror("mkfifo");}int fd = open(FILE_NAME , O_RDONLY); //只读形式打开if(fd < 0){perror("open error!\n");return 2;}char buf[128];while(1){ssize_t s = read(fd ,buf, sizeof(buf)-1); //开始读数据if(s > 0){buf[s] = 0;printf("client# %s\n" , buf);}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 error!\n");return 1;}char buf[128];while(1){printf("Please Enter# "); //提示语句fflush(stdout);ssize_t s = read(0 , buf , sizeof(buf)); //从键盘中读取数据if(s > 0){buf[s-1] = 0; //输入时多了一个\nwrite(fd , buf ,strlen(buf)); //把读取到的数据写到管道中}}return 0;
}
④运行结果
客户端写入的信息进入命名管道当中,服务端再从命名管道当中将信息读取出来打印在服务端的显示器上,该现象说明服务端是能够通过命名管道获取到客户端发来的信息的,换句话说,此时这两个进程之间是能够通信的。

通过ps命令查看这两个进程的信息,可以发现这两个进程确实是两个毫不相关的进程,因为它们的PID和PPID都不相同

⑤client 和 server 谁先退出问题
1) 客户端先退出,服务端将管道当中的数据读完后就再也读不到数据了,那么此时服务端也就会去执行它的其他代码了(在当前代码中是直接退出了)。

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

⑥通信是在内存当中进行的
client端代码不变 ,server端只是以读的方式打开,但是不读取数据 :

运行程序前后两次查看myfifo管道文件的大小始终为0,说明了双方进程之间的通信依旧是在内存当中进行的,和匿名管道通信是一样的。
(2)通过命名管道,派发计算任务
①两个进程之间的通信,并不是简单的发送字符串而已,服务端是会对客户端发送过来的信息进行某些处理的 ; 这里我们的client端发送计算任务,server端将数据计算出来并打印到显示器上。
②client端的代码没有发生变化,只是server端读取数据时对数据进行了一些处理:
#include "comm.h"int main()
{if(mkfifo(FILE_NAME , 0644) < 0){ //创建管道文件perror("mkfifo");}int fd = open(FILE_NAME , O_RDONLY); //只读形式打开if(fd < 0){perror("open error!\n");return 2;}char buf[128];while(1){ssize_t s = read(fd ,buf, sizeof(buf)-1); //开始读数据if(s > 0){buf[s] = 0;//简单计算char *p = buf;const char *lable="+-*/%";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(buf, "+-*/%"); //通过算数符号将左右两个数字分开char *data2 = strtok(NULL, "+-*/%");int x = atoi(data1); //将字符转整形计算int y = atoi(data2);int z = 0;switch(flag){case 0:z = x + y;break;case 1:z = x - y;break;case 2:z = x * y;break;case 3:z = x / y;break;case 4:z = x % y;break;}printf("%d %c %d = %d\n", x,lable[flag], y, z);}else if(s == 0){printf("client quit!\n");break;}else{printf("read error!\n");break;}}close(fd);return 0;
}
③结果

(3)通过命名管道,进行命令操作
①我们可以通过一个进程来控制另一个进程的行为,比如我们从客户端输入命令到管道当中,再让服务端将管道当中的命令读取出来并执行。简单实现了让服务端执行不带选项的命令,若是想让服务端执行带选项的命令,可以对管道当中获取的命令进行进一步的解析处理。
②client端的代码不变,server端对于输入的数据进行解析,如果有命令则执行:
#include "comm.h"int main()
{if(mkfifo(FILE_NAME , 0644) < 0){ //创建管道文件perror("mkfifo");}int fd = open(FILE_NAME , O_RDONLY); //只读形式打开if(fd < 0){perror("open error!\n");return 2;}char buf[128];while(1){ssize_t s = read(fd ,buf, sizeof(buf)-1); //开始读数据if(s > 0){buf[s] = 0;printf("client# %s\n" , buf);//执行命令if(fork() == 0){ //childexeclp(buf , buf ,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;
}

(4)通过命名管道,进行文件拷贝
①大致思路是,client端将log.txt 文件通过管道发送给server端,server端读取管道中的数据创建一个本地文件,将数据拷贝到本地文件中,以此来实现文件的拷贝。(本实验是在同一个机器上,且在同一个目录下,所以发送文件的文件名不能和接受文件的文件名重复)
②client端代码 : 以读的方式打开log.txt文件 , 以写的方式打开管道文件 ,将log.txt文件中的数据写到管道中.
#include "comm.h"int main()
{int fd = open(FILE_NAME, O_WRONLY); //以写的方式打开命名管道文件if (fd < 0){perror("open");return 1;}int fdin = open("log.txt", O_RDONLY); //以读的方式打开log.txt文件if (fdin < 0){perror("open");return 2;}char buf[128];while (1){//从log.txt文件当中读取数据ssize_t s = read(fdin, buf, sizeof(buf));if (s > 0){write(fd, buf, s); //将读取到的数据写入到命名管道当中}else if (s == 0){printf("read end of file!\n");break;}else{printf("read error!\n");break;}}close(fd); //通信完毕,关闭命名管道文件close(fdin); //数据读取完毕,关闭log.txt文件return 0;
}
③server端代码 : 以读的方式打开管道文件(没有管道文件创建) , 以写的方式在本地创建一个log-bat.txt文件,并将管道中的数据写到log-bat.txt文件中。
#include "comm.h"int main()
{if(mkfifo(FILE_NAME , 0644) < 0){ //创建管道文件perror("mkfifo");}int fd = open(FILE_NAME , O_RDONLY); //只读形式打开if(fd < 0){perror("open error!\n");return 2;}int fdout = open("log-bat.txt" , O_WRONLY|O_CREAT , 0644);if(fdout < 0){perror("open error!\n");return 3;}char buf[128];while(1){ssize_t s = read(fd ,buf, sizeof(buf)-1); //开始读数据if(s > 0){write(fdout , buf , s); //将数据从管道写入文件}else if(s == 0){printf("client quit!\n");break;}else{printf("read error!\n");break;}}close(fd); //通信关闭,关闭管道文件描述符close(fdout); //数据写入完毕return 0;
}

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

(5). 命名管道和匿名管道的区别
- 匿名管道由pipe函数创建并打开。
- 命名管道由mkfifo函数创建,由open函数打开。
- FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在于它们创建与打开的方式不同,一旦这些工作完成之后,它们具有相同的语义。
5.命令行中的管道理解
(1)使用cat 和 grep 命令 , 利用 管道 “ | ” 对信息进行过滤。

(2)管道“ | ” 是匿名管道还是命名管道 ?
①由于匿名管道只能用于有亲缘关系的进程之间的通信,而命名管道可以用于两个毫不相关的进程之间的通信,因此我们可以先看看命令行当中用管道(“|”)连接起来的各个进程之间是否具有亲缘关系。
②通过管道连接了三个进程,通过ps命令查看这三个进程可以发现,这三个进程的PPID是相同的,也就是说它们是由同一个父进程创建的子进程。

③三个sleep进程的父进程是bash ,三个sleep进程互为兄弟

④结论
若是两个进程之间采用的是命名管道,那么在磁盘上必须有一个对应的命名管道文件名,而实际上我们在使用命令的时候并不存在类似的命名管道文件名,因此命令行上的管道实际上是匿名管道。
相关文章:
【Linux】进程间通信2——命名管道
1. 命名管道(FIFO) 1.1. 基本概念 简单,给匿名管道起个名字就变成了命名管道 那么如何给 匿名管道 起名字呢? 结合文件系统,给匿名管道这个纯纯的内存文件分配 inode,将文件名与之构建联系,关键点在于不给它分配 D…...
语音翻译软件app排名来啦,这些工具让旅游畅通无阻
#这个夏天我们一定要去看海# 出国旅行时,语言障碍常常是最让人头疼的问题之一。 特别是在像缅甸这样英语并不普及的国家,基本的日常交流,比如用餐或问路,都可能成为难题。 然而,随着技术的进步,现在有了…...
nginx脚本原理if指令实现详解
之前的文章我们探讨了nginx的变量,接着就是脚本原理,也就是复杂变量,理解了前面的实现原理,接下来了解if,break,return,set就要简单多。 指令有不少,没必要全部探讨,了解了其中之一…...
数据提取与治理:企业数字化转型的双引擎
在当今数字化浪潮中,企业正面临着前所未有的挑战和机遇。为了在这场变革中立于不败之地,数字化转型成为了企业不可或缺的战略选择。而在数字化转型的众多关键要素中,数据提取与治理技术无疑扮演着至关重要的角色,它们如同双引擎一…...
Java8 新特性 记录【持续更新】
目录 一、Stream 相关 1、findFirst 方法 二、Optional 1、如何构造Optional 2、ifPresent 方法 一、Stream 相关 1、findFirst 方法 Stream的findFirst方法在此流中查找第一个元素作为Optional。 如果流中没有元素,findFirst返回空的Optional。 如果流没…...
Protobuf详解及入门指南
Protobuf详解及入门指南 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!在分布式系统和跨平台通信中,高效、轻量的序列化协议尤为重要。Google的Pro…...
[Java基本语法] 逻辑控制与方法
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏:🍕 Collection与数据结构 (92平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 🧀线程与…...
新手教学系列-基础知识(SSH使用)
基础知识(SSH使用) 什么是ssh Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境[1]。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接[2]。虽然任何网络服务都可以通过SSH实现安全传输,SS…...
如何通过细节处理,让展馆展示效果倍增?
如今,企业展览馆已经成为企业树立形象、产品推广的重要平台,他们利用当下流行的多媒体技术,精心设计出一个展览馆,不仅能够吸引观众的眼球,还能够让企业品牌形象更加突出,不过想要制作出一个优质的企业展览…...
汽车IVI中控开发入门及进阶(二十九):i.MX6
前言: i.MX 6双/6Quad处理器集成多媒体应用处理器,是不断增长的多媒体产品系列的一部分,提供高性能处理,并针对最低功耗进行了优化。 i.MX 6Dual/6Quad处理器采用先进的quad-ArmCortex-A9内核,运行速度高达800 MHz,包括2D和3D图形处理器、1080p视频处理和集成电源管理。…...
2024-Pop!_OS新版本,新桌面环境的消息
原文:A Blog to Satisfy Your Monthly COSMIC Fix(es) - System76 Blog Pop!_OS开发团队正在为他们的发行版开发一个定制桌面。这个新的桌面环境被称为COSMIC,是用Rust语言编写的,超快的COSMIC应用商店几乎已经实现!alpha版本只剩下一些次要…...
三分钟了解链动3+1模式
在电商领域的营销策略中,链动31模式以其独特的魅力和优势,吸引了众多商家的目光。下面,我们将对这一模式进行深度剖析,并探讨其相较于链动21模式的优势所在。 一、身份设置与奖励机制 链动31模式在身份设置上分为三种࿱…...
加密excel(Python)
文章目录 一、EXCEL加密 一、EXCEL加密 import randomfrom win32com.client import Dispatchdef random_password(length20):默认返回20位随机密码key ""characters "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"for i in range(l…...
解决Unity-2020 安卓异形屏黑边
背景 Unity 2020.3.17 版本开发的游戏,打apk包,发现两个问题 如图下午所示,实体白色导航栏,阻挡了整个安卓UI界面,难看还影响美观。 安卓系统 12-13 版本手机,异形屏。一侧安全区黑边遮挡,占空间…...
python-给你比个五彩斑斓的❤️
import numpy as np import matplotlib.pyplot as plt from matplotlib.collections import LineCollectiont np.linspace(0, 2 * np.pi, 1000) x 16 * np.sin(t)**3 y 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t)# 创建一个颜色序列 colors …...
【Go】使用Go语言实现AES CBC No Padding加密和解密
冷雨悄悄停吧 天真的心因为你 那管多风雨天仍和你一起 告诉你我其实多么的想你 其实我我真的爱着你 🎵 蒋明周《真的爱着你》 引言 高级加密标准(AES)是一种广泛使用的加密算法。它可以工作在多种模式下,最…...
安装VS Code 提示This User Installer is not meant to be run as an Administrator问题
目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 在vs code官网(https://code.visualstudio.com/)下载安装包,显示如下提示信息: This User Installer is not meant to be run as an Administrator.…...
keepalived服务详解与实验 基于centos8
目录 keepalivedHA简介常用的高可用软件keepalived简介 keepalived常用模块keepalived功能简介keepalived常用文件keepalived配置文件详解keepalived实验1-上手环境准备安装服务主配置文件修改启动服务效果查看 keepalived脑裂1. 脑裂现象简介2. 脑裂的原因3. 脑裂的预防和解决…...
vue技巧(十)全局配置使用(打包后可修改配置文件)
1、背景 vue打包目前主流用的有webpack和vite两种,默认用的webpack。(二者的区别大家可以各自上网查,我没用过vite,所以不过多介绍)vue通过webpack打包后,源码会被压缩,但一些关键配置可…...
计算机网络 —— 运输层(运输层概述)
计算机网络 —— 运输层(运输层概述) 运输层运输层端口号复用分用复用(Multiplexing)分用(Demultiplexing) 常用端口号页面响应流程 我们今天进入到运输层的学习: 运输层 我们之前学习的物理层…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

不同于匿名管道之处在于它提供一个路径名与之关联,以

