Linux实验六:进程间通信(二)

目录

    • 一、实验目的
    • 二、实验内容
    • 三、实验环境
    • 四、参考代码
    • 五、实验步骤
      • 步骤1. 编辑源代码test6.c
      • 步骤2. 编译源代码test6.c
      • 步骤3. 运行可执行程序test6
      • 步骤4. 进一步调试源代码test6.c
    • 六、实验结果
    • 七、实验总结


一、实验目的

1、理解 POSIX 和 System V 提供的 IPC 相关概念;
2、理解管道所使用的文件描述符数组如何实现父子进程间的通信;
3、掌握 IPC 常用的函数,如 pipe,mkfifo 等。

二、实验内容

根据应用需要,父进程A需向子进程B传输消息 “Message here”,请使用管道技术完成此功能。

三、实验环境

虚拟机软件:VMware 16 Pro
Linux操作系统版本:CentOS-7-64位

四、参考代码

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

int main(int argc,char* argv[]){
    pid_t pid;
    int fds[2];
    char buf[256];
    const char data[]="Message here!";
    int len=0;

    memset((void*)buf,0,sizeof(buf));

    //create pipe
    if(pipe(fds)<0){
        printf("Pipe create error!\n");
        exit(-1);
    }

    //create child process
    if((pid=fork())==0){
        close(fds[1]);
        if((len=read(fds[0],buf,strlen(data)))!=-1){
            printf("B read from A:%s!\n",buf);
        }
        close(fds[0]);
    }else if(pid>0){
        close(fds[0]);
        if((len=write(fds[1],data,strlen(data)))!=-1){
            printf("A write to B:%s!\n",data);
        }
        close(fds[1]);
        waitpid(pid,NULL,0);
        exit(0);
    }else{
        printf("Create process error!\n");
        exit(-1);
    }
}

五、实验步骤

步骤1. 编辑源代码test6.c

源代码test6.c内容见上述参考代码。

mkdir test6
cd test6
vim test6.c

在这里插入图片描述

这段代码是一个简单的父子进程间通信的例子,使用了Linux系统调用中的管道(pipe)和进程创建(fork)。

  • 在main函数中,定义了一些变量,包括一个pid_t类型的pid变量用于存储进程ID,一个整型数组fds用于存储管道的文件描述符,一个字符数组buf用于存储读取的数据,一个常量字符数组data存储要写入管道的数据,以及一个整型变量len用于存储读取或写入的字节数。

  • 使用memsetbuf数组初始化为0,以确保没有垃圾数据残留。

  • 调用pipe函数创建管道,如果失败,则打印错误信息并退出程序。

  • 调用fork函数创建子进程。如果fork返回值为0,表示当前代码正在子进程中执行;如果大于0,表示当前代码正在父进程中执行;如果返回-1,表示创建进程失败。

  • 如果在子进程中,关闭了fds数组的写端(fds[1]),然后通过read函数从管道的读端(fds[0])读取数据到buf数组中,并打印读取的数据。

  • 如果在父进程中,关闭了fds数组的读端(fds[0]),然后通过write函数将data数组中的数据写入管道的写端(fds[1]),并打印写入的数据。

  • 在父进程中调用waitpid函数等待子进程退出。

  • 父子进程均关闭了管道的相应端口,并退出程序。

这段代码实现了父子进程间的单向通信,父进程向子进程写入数据,子进程读取并打印收到的数据。

步骤2. 编译源代码test6.c

gcc test6.c -o test6 -g

在这里插入图片描述

步骤3. 运行可执行程序test6

./test6

在这里插入图片描述

步骤4. 进一步调试源代码test6.c

(1)将父进程发给子进程的消息“Message here”,改为发送:自己的学号和姓名(使用 \n 分隔);

pid_t pid;
int fds[2];
char buf[256];
const char data[]="\n学号:123456789\n姓名:zhc";
int len=0;

(2)子进程运行结束前,输出“子进程在这里结束\n”;

if((pid=fork())==0){
    close(fds[1]);
    if((len=read(fds[0],buf,strlen(data)))!=-1){
        printf("B read from A:%s!\n",buf);
    }
    close(fds[0]);
    printf("子进程在这里结束\n");
}

(3)父进程运行结束前,输出“父进程结束\n”。

else if(pid>0){
    close(fds[0]);
    if((len=write(fds[1],data,strlen(data)))!=-1){
        printf("A write to B:%s!\n",data);
    }
    close(fds[1]);
    waitpid(pid,NULL,0);
    printf("父进程结束\n");
    exit(0);
}

再重新编译test6.c,并运行可行性文件test6。结果如下图所示:

在这里插入图片描述

六、实验结果

调试后的最终源代码test6.c:

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

int main(int argc,char* argv[]){
    pid_t pid;
    int fds[2];
    char buf[256];
    const char data[]="\n学号:123456789\n姓名:zhc";
    int len=0;

    memset((void*)buf,0,sizeof(buf));

    //create pipe
    if(pipe(fds)<0){
        printf("Pipe create error!\n");
        exit(-1);
    }

    //create child process
    if((pid=fork())==0){
        close(fds[1]);
        if((len=read(fds[0],buf,strlen(data)))!=-1){
            printf("B read from A:%s!\n",buf);
        }
        close(fds[0]);
        printf("子进程在这里结束\n");
    }else if(pid>0){
        close(fds[0]);
        if((len=write(fds[1],data,strlen(data)))!=-1){
            printf("A write to B:%s!\n",data);
        }
        close(fds[1]);
        waitpid(pid,NULL,0);
        printf("父进程结束\n");
        exit(0);
    }else{
        printf("Create process error!\n");
        exit(-1);
     }
}

实验运行结果如下图所示。

在这里插入图片描述

七、实验总结

  通过这次实验,我对进程间通信和Linux系统调用有了更深入的认识。这个简单的例子展示了如何使用管道(pipe)和进程创建(fork)来实现父子进程之间的通信,同时也揭示了一些潜在的问题和注意事项。
  首先,我对管道的理解得到了加深。管道是一种进程间通信的机制,它可以在父子进程之间传递数据。在这个例子中,通过调用pipe函数创建了一个管道,它返回了两个文件描述符,分别用于读取和写入数据。这种单向的通信方式确保了数据的顺序性和可靠性。其次,我对进程创建(fork)有了更清晰的认识。fork函数用于创建一个新的进程,新的进程是调用进程的副本,但有着不同的进程ID。在这个例子中,通过fork函数创建了一个子进程,子进程和父进程共享了文件描述符表,但各自有独立的内存空间,因此可以通过管道进行通信。
  在实验过程中,我也遇到了一些问题。例如,父进程在写入数据后调用了waitpid函数等待子进程退出,这样可以确保子进程在父进程之后退出,防止出现僵尸进程。另外,在子进程中读取数据时,我发现可以使用read函数的返回值来判断是否成功读取数据,这样可以更加健壮地处理错误。
  通过这个实验,我不仅加深了对进程间通信和Linux系统调用的理解,还学会了如何使用管道和进程创建来实现简单的父子进程通信。我相信这些知识将在未来的编程实践中发挥重要作用,让我能够更加高效地编写并理解涉及进程间通信的程序。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安防监控视频平台LntonCVS视频监控汇聚平台遏制校园暴力保护校园学生安全应用方案

未成年人被誉为祖国的花朵&#xff0c;是我们国家的未来。然而&#xff0c;最近频繁曝出的未成年霸凌事件却引发了社会的广泛关注。这些事件手段残忍&#xff0c;事态恶劣&#xff0c;引发了全社会对如何保护未成年身心健康、规避霸凌事件发生的深刻思考。 为了更好地保障学生的…

从零开始:如何用Electron将chatgpt-plus.top 打包成EXE文件

文章目录 从零开始&#xff1a;如何用Electron将chatgpt-plus.top 打包成EXE文件准备工作&#xff1a;Node.js和npm国内镜像加速下载初始化你的Electron项目创建你的Electron应用运行你的Electron应用为你的应用设置图标打包成EXE文件结语 从零开始&#xff1a;如何用Electron将…

echarts学习:将echats实例代理为响应式对象可能带来的风险

1.起源 最近我在学习如何封装echarts组件&#xff0c;我所参考的其中一篇博客中提到了一个“图表无法显示的问题”。 根据其中的介绍&#xff0c;造成此种问题的原因是因为&#xff0c;使用ref接受了echarts实例&#xff0c;使得echarts实例被代理为了响应式对象&#xff0c;进…

[C#]使用C#部署yolov8的obb旋转框检测tensorrt模型

【测试通过环境】 win10 x64 vs2019 cuda11.7cudnn8.8.0 TensorRT-8.6.1.6 opencvsharp4.9.0 .NET Framework4.7.2 NVIDIA GeForce RTX 2070 Super 版本和上述环境版本不一样的需要重新编译TensorRtExtern.dll&#xff0c;TensorRtExtern源码地址&#xff1a;TensorRT-CShar…

3D视觉系统实现自动化上下料操作

在竞争激烈的汽车制造行业&#xff0c;提高生产效率、降低成本并保证产品质量是企业持续发展的关键。特别是在汽车制造过程中&#xff0c;各种零部件的上下料操作占据了大量的生产时间&#xff0c;因此如何实现这些操作的自动化、高效化成为了一个亟待解决的问题。 富唯智能3D视…

pom文件中,Maven导入依赖出现 Dependency not found

解决方案&#xff1a; 1、首先看一下自己的Maven是否配置好了 2、再检查一下镜像是否正确 3、如果上面都没有问题&#xff0c;看 dependencyManagement 标签 我这个出错&#xff0c;爆一大片红就是因为 这个标签 dependencyManagement 解决方法&#xff1a;在父工程中进行依…

在 Kubesphere 中开启新一代云原生数仓 Databend

上周六&#xff0c;由 KubeSphere 社区联合 Databend 社区以及纵目科技共同组织的云原生 Meetup 北京站在北京圆满落幕。本次 Meetup 活动邀请到了 SkyWalking PMC 成员、青云科技架构及可观测性团队负责人、江苏纵目科技 APM 研发总监、青云科技容器产品经理、数元灵科技 CTO …

JVM内存划分类加载的过程双亲委派模型的详解

JVM内存划分 JVM也就是java进程&#xff0c;这个进程一旦跑起来就会从操作系统这里申请一大块内存空间&#xff0c;JVM接下来就要进一步的对这个大的空间进行划分&#xff0c;划分成不同区域&#xff0c;从而每个区域都有不同的功能作用&#xff0c;一共分为如下几个区域 1.堆…

【数据结构】二叉树-堆(下)-链式二叉树

个人主页~ 二叉树-堆&#xff08;上&#xff09; 栈和队列 二叉树 四、堆的代码实现Heap.hHeap.ctest.c 五、堆的应用堆排序思想进行排序 六、二叉树链式结构的实现BTree.hBTree.ctest.c 四、堆的代码实现 Heap.h #pragma once#include <stdio.h> #include <stdlib…

Leetcode:寻找两个正序数组的中位数

题目链接&#xff1a;4. 寻找两个正序数组的中位数 - 力扣&#xff08;LeetCode&#xff09; 题目分析 1、当只有一个有序数组时&#xff0c;该数组的中位数会将该数组分为两份&#xff1a;左子数组 和 右子数组 2、当有两个有序数组时&#xff0c; 我们仍然可以通过一条分隔…

计算机网络之快重传和快恢复以及TCP连接与释放的握手

快重传和快恢复 快重传可以让发送方尽早得知丢失消息&#xff0c; 当发送消息M1,M2&#xff0c;M3,M4,M5后,假如消息M2丢失&#xff0c;那么按照算法会发送对M2报文前一个报文M1的重复确认&#xff08;M1正常接受到&#xff0c;已经发送了确认),然后之后收到M4,M5,也会发送两…

内网安全之注册和查看证书

注册证书 如图所示&#xff0c;是 Will Schroeder 和 Lee Christensen 发布的 Certified_Pre-Owned 白皮书里面画的证书注册流程: 从图中我们可以看到&#xff0c;证书注册流程如下&#xff1a; 客户端生成一对公、私钥。客户端生成证书签名请求(CSR&#xff0c;Certificate…

linux系统——性能检测工具glances

在linux系统中&#xff0c;由python开发的glances工具是一个功能强大的性能检测工具 可以通过yum进行安装 安装glances后&#xff0c;进入命令界面 glance支持网站模式&#xff0c;将监控到的数据以网站形式显示出来 这里需要用python包管理命令 使用glances -w开放…

Java集合-List(Collection子接口)及其子类(ArrayList、Vector、LinkedList)

List接口是 Collection接口的子接口。 1、List集合类中数据有序&#xff0c; 即添加顺序和取出顺序有序&#xff0c;而且可以重复。 2、List集合类中每个元素都有其对应的顺序索引&#xff0c;即支持索引。例&#xff0c;list.get(2)&#xff1b;取第三个元素。 3、实现类有很多…

百度地图1

地图的基本操作 百度地图3.0文档 百度地图3.0实例中心 设置地图 centerAndZoom(center: Point, zoom: Number)设初始化地图,center类型为Point时&#xff0c;zoom必须赋值&#xff0c;范围3-19级&#xff0c; // 百度地图API功能var map new BMap.Map("map"); //…

CentOS8搭载正反向解析dns服务器

1.介绍&#xff08;是什么&#xff09; DNS&#xff08;Domain Name System&#xff09;&#xff0c;即域名系统&#xff0c;是一个将域名和 IP 地址相互映射的分布式数据库&#xff0c;它可以将用户输入的域名转换成对应的 IP 地址。DNS 由多个服务器组成&#xff0c;分为多个…

企业想要搭建一个虚拟展厅需要多少钱?

企业搭建虚拟展厅的费用会根据多种因素有所不同&#xff0c;主要包括展厅的类型、规模、功能需求、技术复杂度以及服务商的定价策略等。以下是关于虚拟展厅搭建费用的分点说明和归纳&#xff1a; 一、展厅类型&#xff1a; 1、全景实拍展厅&#xff1a; 利用VR全景拍摄技术还…

结构体中内存的对齐

前言 学C的同学应该知道~ 想精通C语言就不得不面对—指针与内存 续上次指针进阶&#xff0c;这一章我来聊一聊C语言内存对齐的问题 学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的&#x1f601; 思考 #include<stdio.h> typedef struct s1 {char a;char …

【Python】 如何获取 Python 函数的名称作为字符串?

基本原理 在 Python 中&#xff0c;获取函数名称是一个简单但非常有用的技巧&#xff0c;尤其是当你需要动态地引用函数或者在日志、调试中需要函数名称时。Python 提供了几种方法来获取函数的名称。 方法一&#xff1a;使用 __name__ 属性 每个函数对象都有一个 __name__ 属…

【Unity】使用Jenkins实现远程Unity打包

前言 很多时候&#xff0c;我们需要自动打包&#xff0c;比如下班了&#xff0c;我要出一个包明天早上用。比如每天夜里12点&#xff0c;我需要定时出一个稳定包。 这个时候就需要Jenkins了。 1.安装环境 安装 jenkins 之前&#xff0c;需要安装Java 。Java下载网站 ①下载…