《TCP/IP网络编程》阅读笔记--进程间通信

news2024/10/12 2:21:26

目录

1--进程间通信

2--pipe()函数

3--代码实例

3-1--pipe1.c

3-2--pipe2.c

3-3--pipe3.c

3-4--保存信息的回声服务器端


1--进程间通信

        为了实现进程间通信,使得两个不同的进程间可以交换数据,操作系统必须提供两个进程可以同时访问的内存空间;

        为了完成进程间通信,需要创建管道(pipe);管道并非属于进程的资源,而是属于操作系统;

2--pipe()函数

#include <unistd.h>
int pipe(int filedes[2]);
// 成功时返回0,失败时返回-1
// filedes[0] 通过管道接收数据时使用的文件描述符,即管道出口
// filedes[1] 通过管道传输数据时使用的文件描述符,即管道入口

3--代码实例

3-1--pipe1.c

        子进程从管道入口写数据,父进程从管道出口读数据;

// gcc pipe1.c -o pipe
// ./pipe

#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30

int main(int argc, char *argv[]){
    int fds[2];
    char str[] = "Who are you?";
    char buf[BUF_SIZE];
    __pid_t pid;

    pipe(fds); // 创建管道
    pid = fork();
    if(pid == 0){ // 子进程执行区域
        write(fds[1], str, sizeof(str)); // 向管道入口写数据
    }
    else{ // 父进程执行区域
        read(fds[0], buf, BUF_SIZE); // 向管道出口读数据
        puts(buf);
    }
    return 0;
}

3-2--pipe2.c

        利用一个管道实现父进程与子进程的双向通信;

// gcc pipe2.c -o pipe2
// ./pipe2

#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30

int 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); // sleep的作用是防止子线程写的数据被子线程自身读取了,导致父进程一直等待
        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;
}

3-3--pipe3.c

        利用两个管道实现父进程与子进程的双向通信,其中收发数据在不同的管道上进行;

// gcc pipe3.c -o pipe3
// ./pipe3

#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30

int 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)); // 通过管道1写数据
        read(fds2[0], buf, BUF_SIZE); // 通过管道2读数据
        printf("Child proc output: %s \n", buf);
    }
    else{ // 父进程执行区域
        read(fds1[0], buf, BUF_SIZE); // 通过管道1读数据
        printf("Parent proc output: %s \n", buf);
        write(fds2[1], str2, sizeof(str2)); // 通过管道2写数据
        sleep(3);
    }
    return 0;
}

3-4--保存信息的回声服务器端

        服务器端创建两个进程,一个进程负责与客户端进行通信,将客户端发来的数据通过管道入口写到管道中;另一个进程负责从管道出口中读取数据,并把读取的数据保存在文件中;

        具体可运行代码参考:Chapter11

// gcc echo_storeserv.c -o echo_storeserv
// ./echo_storeserv 9190

#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 30

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("remove proc id: %d \n", pid);
}

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);

    serv_sock = socket(PF_INET, SOCK_STREAM, 0); // 创建 tcp socket
    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){
        error_handling("bind() error"); 
    } 
    if(listen(serv_sock, 5) == -1){
        error_handling("listen() error");
    }

    pipe(fds);
    pid = fork();
    if(pid == 0){ // 子进程执行区域
        FILE* fp = fopen("echomsg.txt", "wt");
        char msgbuf[BUF_SIZE];
        int i, len;

        for(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;
        }
        else{
            puts("new client connected...");
        }

        pid = fork();
        if(pid == 0){
            close(serv_sock);
            while((str_len = read(clnt_sock, buf, BUF_SIZE)) != 0){
                write(clnt_sock, buf, str_len);
                write(fds[1], buf, str_len);
            }
            close(clnt_sock);
            puts("client disconnected...");
            return 0;
        }
        else{
            close(clnt_sock);
        }
    }
    close(serv_sock);
    return 0;

}

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

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

相关文章

初出茅庐的小李博客之数制与编码知识

模拟量与数字量&#xff1a; 数字量和模拟量是两种用于表示和处理不同类型数据的概念&#xff0c;常见于电子和计算机系统中。它们在信号处理、传感器技术、通信和控制系统中有不同的应用。 1. 数字量&#xff08;Digital&#xff09;&#xff1a; 数字量是离散的&#xff0…

06文本搜索工具——grep以及正则表达式

一、grep工具的使用 可以通过返回状态码判断文件有没有这个数据&#xff0c;有状态码为0&#xff0c;没有为1。文件不存在状态码为2 -o&#xff1a; 二、正则表达式 1、基本正则表达式 .为匹配任意字符&#xff0c;..两个两个匹配任意字符&#xff0c;...三个三个匹配任意字符 …

群拼团接龙小程序源码功能和开发

针对微信群开发的拼团接龙小程序&#xff0c;有点快团团的味道。是做私域非常不错的一款小程序。 小程序基于Uniapp开发&#xff0c;目前适配了微信小程序。 接龙&#xff1a; 在小程序中可以创建自定义接龙&#xff0c;不需要复杂的申请流程。 商品发布&#xff1a; 接龙…

模板测试和深度测试在cocoscreator中的应用

模板测试(Stencil Test)&#xff1a; 当片段着色器处理完一个片段之后&#xff0c;模板测试(Stencil Test)会开始执行&#xff0c;和深度测试一样&#xff0c;它也可能会丢弃片段。接下来&#xff0c;被保留的片段会进入深度测试&#xff0c;它可能会丢弃更多的片段。模板测试…

React 开发一个移动端项目(1)

技术栈&#xff1a; 项目搭建&#xff1a;React 官方脚手架 create-react-appreact hooks状态管理&#xff1a;redux 、 redux-thunkUI 组件库&#xff1a;antd-mobileajax请求库&#xff1a;axios路由&#xff1a;react-router-dom 以及 historyCSS 预编译器&#xff1a;sass…

Web开发后端总结

Web后端开发现在基本上都是基于标准的三层架构进行开发的&#xff0c;在三层架构当中&#xff0c;Controller控制器层 - 负责接收请求响应数据&#xff0c;Service - 业务层负责具体的业务逻辑处理&#xff0c;而Dao - 数据访问层也叫持久层&#xff0c;就是用来处理数据访问操…

第9节-PhotoShop基础课程-移动抓手缩放工具

文章目录 前言1. 移动工具1.移动工具1.自动选择&#xff08;图层和组&#xff09;2.显示变换控件 &#xff08;Shift 变换/ Ctrl 变换&#xff09;3.自由变换 Ctrl T &#xff08;Shift 变换/ Ctrl 变换&#xff09;4.对齐功能 2.画板工具 V1. 创建画板并作图2.导出画板 2.路…

【strcpy函数和strncpy函数的对比与模拟实现】

strcpy函数和strncpy函数的对比与模拟实现 1.strcpy函数介绍 资源来源于cplusplus网站 大致意思就是&#xff1a; 它的作用为&#xff1a; 将一个字符串复制到另一块空间地址中 的函数&#xff0c;‘\0’是停止拷贝的终止条件&#xff0c;同时也会将 ‘\0’ 也复制到目标空间…

redis集群最少使用三个主节点和使用16384个槽以及主节点数量不超过1000的原因

目录 集群最少三个主节点的原因 为什么是三个? 为什么是奇数? 16384个槽和1000个主节点 集群最少三个主节点的原因 https://redis.io/docs/management/scaling/ 官网建议&#xff0c;搭建 redis 集群最少三主三从。 但是这么做是出于什么考虑呢&#xff1f; https://workt…

02深度学习目标检测方法介绍-传统

一、目标学习的检测方法变迁及对比 “目标检测“是当前计算机视觉和机器学习领域的研究热点。从Viola-Jones Detector、DPM等冷兵器时代的智慧到当今RCNN、YOLO等深度学习土壤孕育下的GPU暴力美学&#xff0c;整个目标检测的发展可谓是计算机视觉领域的一部浓缩史。整个目标检测…

Python实操 PDF自动识别并提取Excel文件

最近几天&#xff0c;paddleOCR开发了新的功能&#xff0c;通过将图片中的表格提取出来&#xff0c;效果还不错&#xff0c;今天&#xff0c;作者按照步骤测试了一波。 首先&#xff0c;讲下这个工具是干什么用的&#xff1a;它的功能主要是针对一张完整的PDF图片&#xff0c;可…

EasyAVFilter代码示例之将摄像机RTSP流转成RTMP推流输出

以下是一套完整的RTSP流转RTMP推流功能的开发源码&#xff0c;就简简单单几行代码&#xff0c;就可以完成原来ffmpeg很复杂的调用流程&#xff0c;而且还可以集成在自己的应用程序中调用&#xff0c;不需要再单独一个ffmpeg的进程来调用&#xff0c;方法很简单&#xff1a; #i…

spring中的@Configuration配置类和@Component

在Spring的开发工作中&#xff0c;基本都会使用配置注解&#xff0c;尤其以Component及Configuration为主&#xff0c;当然在Spring中还可以使用其他的注解来标注一个类为配置类&#xff0c;这是广义上的配置类概念&#xff0c;但是这里我们只讨论Component和Configuration&…

盲盒小程序开发方案

盲盒游戏作为一种富有趣味性和收藏价的虚拟盲盒产品&#xff0c;近年来在游戏市场中备受关注。本文将深入探讨盲盒游戏的开发方案&#xff0c;从市场趋势分析、用户体验设计、商业模式选择等多个维度&#xff0c;为开发者提供业且有深度的思考&#xff0c;以帮助他们在盲盒游戏…

容器编排学习(八)卷的概述与存储卷管理

一 卷 1 容器化带来的问题 容器中的文件在磁盘上是临时存放的&#xff0c;这给容器中运行的重要的应用程序带来一些问题 问题1&#xff1a;当容器崩溃或重启的时候&#xff0c;kubelet 会以干净的状态(镜像的状态)重启容器&#xff0c;容器内的历史数据会丢失 问题2&…

upload-labs1-17思路

1 直接写一个php文件测试一下&#xff0c;发现弹窗不让上传 原理很简单&#xff0c;就是把后缀名拿出来过滤一遍&#xff0c;而白名单就是弹窗的这三个 解决方法&#xff1a; 因为这是在前端防御的一个手段&#xff0c;所以直接在浏览器设置上禁用js就行了&#xff1a; 也可…

数据结构与算法_栈

一、什么是栈 栈是一种特殊的线性表&#xff0c;它只允许在固定的一端进行插入和删除的操作。 对数据进行插入和删除的一端叫做栈顶&#xff0c;另一端是栈底。 对栈的两项操作分别叫做入栈、出栈。 入栈就是对栈进行插入操作&#xff0c;除此之外&#xff0c;入栈也叫做进…

2023挖漏洞给报酬的网站汇总,兼职副业3天收益2000

一、众测平台(国内)二、前沿漏洞研究奖励计划三、行业SRC四、企业应急响应中心-SRC-汇总 1、互联网企业2、生活服务、住宿、购物相关企业3、物流、出行、旅游4、金融相关企业5、视频游戏直播社交娱乐6、教育、问答、知识付费7、泛科技通讯物联网云服务8、安全企业9、其他 一、…

渗透测试的八大步骤

渗透测试 其实很多安全漏洞都属于Web应用漏洞&#xff0c;这些Web漏洞可以通过渗透测试验证。渗透测试是利用模拟黑客攻击的方式&#xff0c;评估计算机网络系统安全性能的一种方法。这个过程是站在攻击者角度对系统的任何弱点、技术缺陷或漏洞进行主动分析&#xff0c;并且有…

【深度学习】Mini-Batch梯度下降法

Mini-Batch梯度下降法 在开始Mini-Batch算法开始之前&#xff0c;请确保你已经掌握梯度下降的最优化算法。 在训练神经网络时&#xff0c;使用向量化是加速训练速度的一个重要手段&#xff0c;它可以避免使用显式的for循环&#xff0c;并且调用经过大量优化的矩阵计算函数库。…