《TCP IP网络编程》第十一章
第 11 章 进程间通信
11.1 进程间通信的基本概念
通过管道实现进程间通信:
进程间通信,意味着两个不同的进程中可以交换数据。下图是基于管道(PIPE)的进程间通信的模型:
可以看出,为了完成进程间通信,需要创建管道。管道并非属于进程的资源,而是和套接字一样,属于操作系统(也就不是 fork 函数的复制对象)。所以,两个进程通过操作系统提供的内存空间进行通信。下面是创建管道的函数:
#include <unistd.h>
int pipe(int filedes[2]);
/*
成功时返回 0 ,失败时返回 -1
filedes[0]: 通过管道接收数据时使用的文件描述符,即管道出口
filedes[1]: 通过管道传输数据时使用的文件描述符,即管道入口
*/
父进程调用函数时将创建管道,同时获取对应于出入口的文件描述符,此时父进程可以读写同一管道。但父进程的目的是与子进程进行数据交换,因此需要将入口或出口中的 1 个文件描述符传递给子进程。下面的例子是关于该函数的使用方法:
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30int main(int argc, char *argv[])
{int fds[2]; // 用于存储管道的文件描述符,fds[0] 用于读取,fds[1] 用于写入char str[] = "Who are you?"; // 待写入管道的字符串char buf[BUF_SIZE]; // 用于存储从管道读取的数据pid_t pid;// 调用 pipe 函数创建管道,fds 数组中保存用于 I/O 的文件描述符pipe(fds);pid = fork(); // 创建子进程,子进程将同时拥有创建管道获取的2个文件描述符,复制的并非管道,而是文件描述符if (pid == 0) // 子进程{write(fds[1], str, sizeof(str)); // 将字符串写入管道的写入端}else // 父进程{read(fds[0], buf, BUF_SIZE); // 从管道的读取端读取数据puts(buf); // 将读取的数据打印到屏幕上}return 0;
}
运行结果:

可以从程序中看出,首先创建了一个管道,子进程通过 fds[1] 把数据写入管道,父进程从 fds[0] 再把数据读出来。可以从下图看出:

通过管道进行进程间双向通信:
下图可以看出双向通信模型:

下面是双向通信的代码示例:
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30int main(int argc, char *argv[])
{int fds[2];char str1[] = "Who are you?";char str2[] = "Thank you for your message";char buf[BUF_SIZE];pid_t pid;pipe(fds);pid = fork();if (pid == 0){write(fds[1], str1, sizeof(str1));sleep(2);read(fds[0], buf, BUF_SIZE);printf("Child proc output: %s \n", buf);}else{read(fds[0], buf, BUF_SIZE);printf("Parent proc output: %s \n", buf);write(fds[1], str2, sizeof(str2));sleep(3);}return 0;
}
运行结果:

红色结果是正常运行的结果,蓝色是注释掉sleep(2)这行代码之后的结果。
向管道传递数据时,先读的进程会把数据取走。数据在进入管道之后成为无主数据,也就是先通过read函数先读到数据的进程将得到数据,即使是 该进程将此数据传到了管道中。因此,若注释掉那行代码,子进程将读会自己之前向管道放入的数据,结果就是,父进程掉用read函数后无限期等待数据放入管道。
当一个管道不满足需求时,就需要创建两个管道,各自负责不同的数据流动,过程如下图所示:

使用两个管道可以避免程序流程的预测和控制。用上述模型改进的代码示例:
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30int main(int argc, char *argv[])
{int fds1[2], fds2[2];char str1[] = "Who are you?";char str2[] = "Thank you for your message";char buf[BUF_SIZE];pid_t pid;pipe(fds1), pipe(fds2);pid = fork();if (pid == 0){write(fds1[1], str1, sizeof(str1));read(fds2[0], buf, BUF_SIZE);printf("Child proc output: %s \n", buf);}else{read(fds1[0], buf, BUF_SIZE);printf("Parent proc output: %s \n", buf);write(fds2[1], str2, sizeof(str2));}return 0;
}
运行结果:
上面通过创建两个管道实现了功能,此时,不需要额外再使用 sleep 函数。运行结果和上面一样。
11.2 运用进程间通信
保存消息的回声服务器:
下面对第 10 章的服务器端代码进行改进,添加一个功能:
将回声客户端传输的字符串按序保存到文件中。
实现该任务将创建一个新进程,从向客户端提供服务的进程读取字符串信息,下面是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30void error_handling(char *message);
void read_childproc(int sig);int main(int argc, char *argv[])
{int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;int fds[2]; // 用于管道的文件描述符数组pid_t pid;struct sigaction act;socklen_t adr_sz;int str_len, state;char buf[BUF_SIZE];if (argc != 2){printf("Usage: %s <port>\n", argv[0]);exit(1);}act.sa_handler = read_childproc; // 防止僵尸进程sigemptyset(&act.sa_mask);act.sa_flags = 0;state = sigaction(SIGCHLD, &act, 0); // 注册信号处理器,将成功的返回值给 stateserv_sock = socket(PF_INET, SOCK_STREAM, 0); // 创建服务端套接字memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family = AF_INET;serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);serv_adr.sin_port = htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1) // 分配IP地址和端口号error_handling("bind() error");if (listen(serv_sock, 5) == -1) // 进入等待连接请求状态error_handling("listen() error");pipe(fds); // 创建管道,fds[0] 用于从子进程读取数据,fds[1] 用于向子进程写入数据pid = fork();if (pid == 0){// 子进程运行区域,此部分从客户端接收数据并写入文件FILE *fp = fopen("echomsg.txt", "wt");char msgbuf[BUF_SIZE];int i, len;for (int i = 0; i < 10; i++){len = read(fds[0], msgbuf, BUF_SIZE); // 从管道读取数据fwrite((void *)msgbuf, 1, len, fp); // 将数据写入文件}fclose(fp);return 0;}while (1){adr_sz = sizeof(clnt_adr);clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz);if (clnt_sock == -1)continue;elseputs("new client connected...");pid = fork();if (pid == 0){// 子进程运行区域,此部分向客户端提供回声服务close(serv_sock); // 关闭服务器套接字,因为从父进程传递到了子进程while ((str_len = read(clnt_sock, buf, BUFSIZ)) != 0){write(clnt_sock, buf, str_len); // 回送数据给客户端write(fds[1], buf, str_len); // 将数据写入管道,供子进程读取写入文件}close(clnt_sock);puts("client disconnected...");return 0;}elseclose(clnt_sock); // 通过 accept 函数创建的套接字文件描述符已经复制给子进程,因为服务器端要销毁自己拥有的}close(serv_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}void read_childproc(int sig)
{pid_t pid;int status;pid = waitpid(-1, &status, WNOHANG);printf("removed proc id: %d \n", pid);
}
该代码创建了一个服务器,并使用多进程处理客户端连接。每当有新的客户端连接到服务器时,会创建一个新的子进程来处理与该客户端的通信。子进程将接收来自客户端的数据,并将数据回送给客户端。同时,子进程还会将收到的数据写入到名为"echomsg.txt"的文件中。父进程用于接受客户端的连接,并通过管道将客户端发送的数据传递给子进程进行处理。
配合第十章的客户端代码运行结果:
服务器端:

客户端:

生成的txt文件:

从图上可以看出,服务端已经生成了文件,把客户端的消息保存下来。
习题 :
1、什么是进程间通信?分别从概念和内存的角度进行说明。
从概念上讲,进程间通信是指两个或多个进程之间交换数据、共享资源或进行通信的机制。它允许不同进程之间进行数据传递和信息交换,从而实现协作和资源共享。
从内存的角度来看,进程间通信意味着不同进程之间需要访问彼此的内存空间。由于每个进程有独立的虚拟内存空间,进程间不能直接访问对方的内存。因此,需要通过特定的IPC机制,如管道、共享内存、消息队列、信号量等,来实现数据的传递和共享。
2、进程间通信需要特殊的 IPC 机制,这是由于操作系统提供的。进程间通信时为何需要操作系统的帮助?
为了进行进程间通信,需要管道的帮助,但是管道不是进程的资源,它属于从操作系统,所以,两个进程通过操作系统提供的内存空间进行通信。
操作系统作为进程的管理者和协调者,提供了特殊的IPC机制。这样,进程间可以协同工作,共享信息和资源,实现复杂的计算和任务。同时,操作系统对进程间通信进行控制和保护,确保系统的稳定性和安全性。
3、「管道」是典型的 IPC 技法。关于管道,请回答以下问题:
i、管道是进程间交换数据的路径。如何创建此路径?由谁创建?
使用 pipe 函数进行创建,由操作系统创建。父进程调用该函数时将创建管道。+
ii、为了完成进程间通信。2 个进程要同时连接管道。那2 个进程如何连接到同一管道?
数组中有两个文件描述符,父子进程调用相关函数时,通过 fork 函数,把 1 个文件描述符传递给子进程。
iii、 管道允许 2 个进程间的双向通信。双向通信中需要注意哪些内容?
向管道传输数据时,先读的进程会把数据取走。简言之,就是数据进入管道后会变成无主数据,会被先调用read函数的进程读取,这个进程可能是自己。所以有时候为了防止错误,需要多个管道来进程通信。
相关文章:
《TCP IP网络编程》第十一章
第 11 章 进程间通信 11.1 进程间通信的基本概念 通过管道实现进程间通信: 进程间通信,意味着两个不同的进程中可以交换数据。下图是基于管道(PIPE)的进程间通信的模型: 可以看出,为了完成进程间通信&…...
Folx Pro 5 最好用的Mac磁力链接BT种子下载工具
除了迅雷,还有哪个支持磁力链接下载?Mac电脑如何下载磁力链接?经常有小伙伴问老宅。今天,老宅给大家推荐Folx Pro For Mac,Mac系统超好用的磁力下载工具。 Folx是一款功能强大且易于使用的Mac下载管理器,并…...
Redis 数据库的高可用
文章目录 Redis 数据库的高可用一.Redis 数据库的持久化1.Redis 高可用概念2.Redis 实现高可用的技术2.1 持久化2.2 主从复制2.3 哨兵2.4 Cluster集群 3.Redis 持久化3.1 持久化的功能3.2 Redis 提供持久化的方式3.2.1 RDB 持久化3.2.2 AOF 持久化(append only file…...
elementPlus dialog组件设置可拖动,当内容高度大于视口高度拖动显示异常的解决办法
elementPlus UI的dialog弹框组件在设置了draggable属性后就可拖动弹框,但是当弹框的内容高度大于视口高度时去拖动弹框就会出现显示问题。 解决办法(修改源码) 去node_modules下面找到element-plus文件夹,按照以下路径修改onMou…...
亲测解决Git inflate: data stream error (incorrect data check)
Git inflate: data stream error (incorrect data check) error: unable to unpack… 前提是你的repository在github等服务器或者其他路径有过历史备份/副本,不要求是最新版本的,只要有就可能恢复你做的所有工作。 执行git fsck --full检查损坏的文件 在…...
Ansible 自动化运维工具
Ansible 简介 Ansible 自动化运维工具(机器管理工具)可以实现批量管理多台(成百上千)主机,应用级别的跨主机编排工具。现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点,Pubbet和Saltstac…...
node.js 爬虫图片下载
主程序文件 app.js 运行主程序前需要先安装使用到的模块: npm install superagent --save axios要安装指定版,安装最新版会报错:npm install axios0.19.2 --save const {default: axios} require(axios); const fs require(fs); const superagent r…...
VAE-根据李宏毅视频总结的最通俗理解
1.VAE的直观理解 先简单了解一下自编码器,也就是常说的Auto-Encoder。Auto-Encoder包括一个编码器(Encoder)和一个解码器(Decoder)。其结构如下: 自编码器是一种先把输入数据压缩为某种编码, 后仅通过该编…...
【LangChain】检索器之上下文压缩
LangChain学习文档 【LangChain】检索器(Retrievers)【LangChain】检索器之MultiQueryRetriever【LangChain】检索器之上下文压缩 上下文压缩 LangChain学习文档 概要内容使用普通向量存储检索器使用 LLMChainExtractor 添加上下文压缩(Adding contextual compression with an…...
uniapp 语音文本播报功能
最近uniapp项目上遇到一个需求 就是在接口调用成功的时候加上语音播报 , ‘创建成功’ ‘开始成功’ ‘结束成功’ 之类的。 因为是固定的文本 ,所以我先利用工具生成了 文本语音mp3文件,放入项目中,直接用就好了。 这里用到的工…...
腾讯云高IO型云服务器CPU型号处理器主频性能
腾讯云服务器高IO型CVM实例CPU处理器主频性能说明,高IO型云服务器具有高随机IOPS、高吞吐量、低访问延时等特点,适合对硬盘读写和时延要求高的高性能数据库等I/O密集型应用,腾讯云服务器网分享高IO型云服务器IT5和IT3的CPU处理器说明…...
【数据结构】实验八:树
实验八 树 一、实验目的与要求 1)理解树的定义; 2)掌握树的存储方式及基于存储结构的基本操作实现; 二、 实验内容 题目一:采用树的双亲表示法根据输入实现以下树的存储,并实现输入给定结点的双亲结点…...
kafka消费者api和分区分配和offset消费
kafka消费者 消费者的消费方式为主动从broker拉取消息,由于消费者的消费速度不同,由broker决定消息发送速度难以适应所有消费者的能力 拉取数据的问题在于,消费者可能会获得空数据 消费者组工作流程 Consumer Group(CG&#x…...
【驱动开发day4作业】
头文件代码 #ifndef __HEAD_H__ #define __HEAD_H__ typedef struct{unsigned int MODER;unsigned int OTYPER;unsigned int OSPEEDR;unsigned int PUPDR;unsigned int IDR;unsigned int ODR; }gpio_t; #define PHY_LED1_ADDR 0X50006000 #define PHY_LED2_ADDR 0X50007000 #…...
Ubuntu 20.04 Ubuntu18.04安装录屏软件Kazam
1.在Ubuntu Software里面输入Kazam,就可以找不到这个软件,直接点击install就可以了 2.使用方法: 选择Screencast(录屏) Fullscreen(全屏)-----Windows(窗口)--------Ar…...
ADC 的初识
ADC介绍 Q: ADC是什么? A: 全称:Analog-to-Digital Converter,指模拟/数字转换器 ADC的性能指标 量程:能测量的电压范围分辨率:ADC能辨别的最小模拟量,通常以输出二进制数的位数表示,比如&am…...
MMdetection框架速成系列 第07部分:数据增强的N种方法
MMdetection框架实现数据增强的N种方法 1 为什么要进行数据增强2 数据增强的常见误区3 常见的六种数据增强方式3.1 随机翻转(RandomFlip)3.2 随机裁剪(RandomCrop)3.3 随机比例裁剪并缩放(RandomResizedCrop࿰…...
基于Kitti数据集的智能驾驶目标检测系统(PyTorch+Pyside6+YOLOv5模型)
摘要:基于Kitti数据集的智能驾驶目标检测系统可用于日常生活中检测与定位行人(Pedestrian)、面包车(Van)、坐着的人(Person Sitting)、汽车(Car)、卡车(Truck…...
4.4. 深拷贝 vs 浅拷贝
文章目录 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为…...
网络安全(黑客)自学建议笔记
前言 网络安全,顾名思义,无安全,不网络。现如今,安全行业飞速发展,我们呼吁专业化的 就职人员与大学生 ,而你,认为自己有资格当黑客吗? 本文面向所有信息安全领域的初学者和从业人员…...
G-Helper完整指南:三步掌握华硕笔记本性能优化神器
G-Helper完整指南:三步掌握华硕笔记本性能优化神器 【免费下载链接】g-helper Lightweight, open-source control tool for ASUS laptops and ROG Ally. Manage performance modes, fans, GPU, battery, and RGB lighting across Zephyrus, Flow, TUF, Strix, Scar,…...
通信萌新们注意了!今天咱们玩点刺激的——用MATLAB手搓各种QAM调制的性能对比。准备好你的小本本,咱们边写代码边分析,包教包会
基于4QAM,16QAM,64QAM调制方式下经过AWGN信道的性能分析 均包含加噪声前后的星座图、误码率和误符号率性能对比,该程序一共10张仿真图,可学习性非常强先上硬货,看看怎么生成4QAM的星座图。掏出这段代码: M …...
不止于上传预览:在若依框架中构建一个轻量级企业文档管理模块
若依框架下的企业级文档中心设计与实战 在数字化转型浪潮中,企业文档管理正从简单的文件存储向智能化协作平台演进。基于若依微服务框架构建文档中心模块,不仅能满足基础的PDF上传预览需求,更能为企业提供版本控制、权限管理、全文检索等进阶…...
基于企业发展过程的改进型元启发式算法IED:一种高效智能优化策略的探索与应用
改进企业发展优化算法IED,(Enterprise Development, ED)是一种新型的元启发式算法(智能优化算法),灵感来源于企业的发展过程。 该算法清晰易懂,与我们日常使用的优化算法相近,发表的期刊等级很高࿰…...
逆向工程实现原理深度解析:Hook技术高效突破百度网盘macOS版系统限制
逆向工程实现原理深度解析:Hook技术高效突破百度网盘macOS版系统限制 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS BaiduNetdiskPlugin-m…...
实战指南:基于快马AI生成贴合业务场景的问卷系统,超越通用opencode
在开发一个在线问卷调查系统时,很多开发者会直接使用现成的opencode或开源组件。但实际业务中,通用方案往往难以完全匹配特定需求。最近我在InsCode(快马)平台上尝试了一个实战项目,通过AI生成高度定制化的问卷系统后台API,效果远…...
Youtu-VL-4B-Instruct-GGUF助力开源社区:如何向GitHub提交高质量的模型使用案例
Youtu-VL-4B-Instruct-GGUF助力开源社区:如何向GitHub提交高质量的模型使用案例 1. 引言:从使用者到贡献者 不知道你有没有这样的经历:在网上找到一个看起来很酷的开源项目,兴致勃勃地打开它的GitHub页面,结果发现文…...
OpenClaw FPGA资源利用率优化深度指南
OpenClaw FPGA资源利用率优化深度指南🔧 核心价值:OpenClaw实现"资源分析→智能优化→验证→部署"全流程自动化,资源利用率平均提升45%,功耗降低38%,时序性能提升28%,支持Xilinx/Intel FPGA全系列…...
保姆级教程:用Nordic NRF52832搞定SIF一线通协议收发(附完整代码)
Nordic NRF52832实战:SIF一线通协议全双工通信开发指南 在物联网设备开发中,单线通信协议因其布线简单、成本低廉而广受欢迎。SIF(Single Interface)作为一种轻量级一线通协议,特别适合传感器与控制器之间的短距离数据…...
013、部署篇:从本地开发到云原生(Docker/K8s)服务化部署
013、部署篇:从本地开发到云原生(Docker/K8s)服务化部署一、从一次深夜调试说起 上周三凌晨两点,我被报警短信吵醒——线上RAG服务的响应时间从200ms飙到了5秒。登录服务器一看,CPU跑满了,内存倒是还剩不少…...
