Linux-应用编程-学习总结(3):进程间通信(上)

前言

这次对进程间通信进行总结。^ ~ ^
上一篇文章以及介绍完了进程的创建,进程的性质,进程的5种状态,改变进程中程序的办法(exec族函数),对进程回收的方法(wait函数)

但是我们可以发现,在进程与进程间的交流,也就是通信还没有了解。这篇文章,将详细的讲述进程间通信的各种方式。

进程间通信相关概念

  1. 什么是IPC
    IPC就是进程间通信的英文缩写(InterProcess Communication)
  2. 进程间通信常用的4种方式
    (1) 管道-简单
    (2) 信号-系统开销小
    (3)共享映射区-(有无血缘关系的进程间通信都可以)
    (4)本地套接字-稳定

管道

管道的概念

本质:
内核缓冲区
伪文件-不占磁盘空间
特点:
两部分:
读端,写端,对应两个文件描述符
数据写端流入,读端流出

操作管道的进程被销毁之后,管道自动被释放
管道默认是阻塞的。

管道的原理

内部实现方式:队列
环形队列
特点:先进先出
缓冲区大小:
默认4k
大小会根据实际情况做适当调整

管道的局限性

队列:
数据只能读取一次,不能重复读取
半双工:
数据的流向是单向的
匿名管道:
适用于有血缘关系的进程

创建匿名管道

int pipe(int fd[2]);
fd-传出元素
fd[0]-读端
fd[1]-写端

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

int main(int argc, const char* argv[])
{
    int fd[2];
    int ret  = pipe(fd);
    if(ret == -1)
    {
        perror("pipe error");
        exit(1);
    }

    printf("fd[0] = %d\n", fd[0]);
    printf("fd[1] = %d\n", fd[1]);
    return 0;
}

在这里插入图片描述
再看一个例子:

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

int main(int argc, const char* argv[])
{
    int fd[2];
    int ret  = pipe(fd);
    if(ret == -1)
    {
        perror("pipe error");
        exit(1);
    }

    printf("fd[0] = %d\n", fd[0]);
    printf("fd[1] = %d\n", fd[1]);

    pid_t pid = fork();
    if(pid == -1)
    {
        perror("fork error");
        exit(1);
    }

    // 父进程 写,关闭读操作
    if(pid > 0)
    {
        sleep(1);
        close(fd[0]);
        char* p = "hell, world\n";
        write(fd[1], p, strlen(p)+1);
        close(fd[1]);

        wait(NULL);
    }
    else if(pid == 0)
    {
        close(fd[1]);
        char buf[1024];
        read(fd[0], buf, sizeof(buf));
        printf("buf = %s\n", buf);
        close(fd[0]);
    }

    return 0;
}

在这里插入图片描述

fifo(有名管道)

特点

有名管道
在磁盘上有这样一个文件ls -l -> p
伪文件,在磁盘的大小永远为0
在内核中有一个对应的缓冲区
半双工的通信方式

使用场景

没有血缘关系的进程间通信

创建方式

命令:mkfifo管道名
直接看代码例子:
wirte_fifo

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

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
        printf("./a.out fifoname\n");
        exit(1);
    }

    // 判断文件是否存在
    int ret = access(argv[1], F_OK);
    if(ret == -1)
    {
        int r = mkfifo(argv[1], 0664);
        if(r == -1)
        {
            perror("mkfifo error");
            exit(1);
        }
        printf("有名管道%s创建成功\n", argv[1]);
    }

    int fd = open(argv[1], O_WRONLY);
    if(fd == -1)
    {
        perror("open error");
        exit(1);
    }
    
    char *p = "hello, world";
    while(1)
    {
        sleep(1);
        int len = write(fd, p, strlen(p)+1);
    }

    close(fd);
    
    return 0;
}

read_fifo

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

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
        printf("./a.out fifoname\n");
        exit(1);
    }

    // 判断文件是否存在
    int ret = access(argv[1], F_OK);
    if(ret == -1)
    {
        int r = mkfifo(argv[1], 0664);
        if(r == -1)
        {
            perror("mkfifo error");
            exit(1);
        }
        printf("有名管道%s创建成功\n", argv[1]);
    }

    int fd = open(argv[1], O_RDONLY);
    if(fd == -1)
    {
        perror("open error");
        exit(1);
    }
    
    char buf[512];
    while(1)
    {
        int len = read(fd, buf, sizeof(buf));
        buf[len] = 0;
        printf("buf = %s\n, len = %d", buf, len);
    }

    close(fd);
    
    return 0;
}

内存映射区

函数原型:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

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


int main(int argc, const char* argv[])
{
    int fd = open("english.txt", O_RDWR);
    if(fd == -1)
    {
        perror("open error");
        exit(1);
    }

    // get file length
    // len > 0
    int len = lseek(fd, 0, SEEK_END);

    void * ptr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(ptr == MAP_FAILED)
    {
        perror("mmap error");
        exit(1);
    }
    close(fd);
 
    char buf[4096];
    // 从内存中读数据
    printf("buf = %s\n", (char*)ptr);
    
	//释放内存映射区
    int ret = munmap(ptr, len);
    if(ret == -1)
    {
        perror("munmap error");
        exit(1);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
进程间通信是指在不同进程之间传输数据或信号的机制。Linux提供了多种进程间通信的方式,包括管道、消息队列、共享内存和信号量等。以下是一些常用的进程间通信方式: 1. 管道(pipe):管道是一种半双工的通信方式,只能在具有亲缘关系的进程之间使用。数据只能单向流动,且在一个进程入的数据只能被另一个进程读取。 2. 命名管道(named pipe):命名管道是一种特殊的文件,可以在不同进程之间共享数据。它允许不具有亲缘关系的进程之间进行通信。 3. 消息队列(message queue):消息队列是一种异步通信方式,进程通过消息队列发送消息,而不需要直接与接收进程进行交互。消息可以按照优先级进行排序,接收进程可以按照顺序接收消息。 4. 共享内存(shared memory):共享内存是一种高效的通信方式,它允许多个进程访问同一块内存空间。这种方式适合于大量数据的传输,但需要考虑同步和互斥等问题。 5. 信号量(semaphore):信号量是一种用于同步和互斥的机制,它可以用于控制进程对共享资源的访问。进程可以通过信号量实现互斥、同步和等待等操作。 在实际的应用中,通常需要结合多种进程间通信方式来实现复杂的功能。比如可以使用消息队列配合共享内存来实现高效的数据传输,或者使用信号量和共享内存来实现进程间的同步和互斥等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值