进程间通信

1. 前言

       进程间通信的方式可谓是面试热点,面试的时候也曾有幸被问到。当时呢是背的面试题,对进程间通信的原理也不是很了解。今天呢就深入了解进程间的通信。

       首先捋一捋进程间的通信有哪几种方式:

  1. socket
  2. 文件
  3. 管道
  4. 共享内存
  5. 信号
  6. 信号量
  7. 消息队列

2. 使用文件实现进程间的通信

       文件:以磁盘作为信息的载体。

       示例:

  • 服务器:提供日期时间服务。

  • 客户端:读取服务器提供的数据或信息。

       基本思想:

  • 服务器进程将数据写入文件
  • 客户端进程从文件中读出数据。
// server.c
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<time.h> 
int main(int argc, char * argv[])
{
    int fd;
    time_t now;
    char *message;
    if (argc!=2)
    {
        printf("errror usage ! \nusage: server filename\n") ;
        exit(1);
    }
    if((fd=open(argv[1],O_CREAT|O_WRONLY|O_TRUNC , 0644))==-1)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        time (&now);
        message=ctime (&now) ;
        // lseek 改变文件读写指针的位置
        // SEEK_SET 文件的开始
        // 因为这里 time 的字节数始终相等,所以覆盖掉之前写的数据,每次文件中只会保存最新的数据
        if( (lseek(fd,0,SEEK_SET))==-1)
        {
            perror("lseek") ;
            exit(1) ;
        }
        if(write (fd, message, strlen(message))==-1)
        {
            perror("write");
            exit(1) ;
        }
        sleep(1);
    }
}
// client.c 

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h> 
#include<fcntl.h>
int main(int argc, char *argv[])
{
    int fd, len;
    char buf[128] ;
    if(argc!=2)
    {
        printf("error usage!\nusage: client filename") ;
        exit(1);
    }
    if((fd=open(argv[1],O_RDONLY))==-1)
    {
        perror("open");
        exit(1);
    }
    while((len=read(fd, buf, 128) )>0)
    {
        write(1, buf ,len) ;
    }
    close(fd) ;
}

在这里插入图片描述

3. 使用管道实现进程间的通信

       管道:以内核空间存放信息。

       管道又分为有名管道和匿名管道,有名管道用于无亲缘关系的进程间通信,而匿名管道则用于有亲缘关系进程间通信。

       示例:

  • 服务器:提供日期时间服务。

  • 客户端:读取服务器提供的数据或信息。

       基本思想:

  • 服务器进程建立命名管道,将数据写入管道。
  • 客户端进程从管道中读出数据。
// server.c

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
int main(int argc, char * argv[])
{
    int fd;
    time_t now ;
    char * message;
    if(argc!=2)
    {
        printf("errror usage! \nusage: server fifoname\n");
        exit(1);
    }
    unlink(argv[1]);
    // 创建有名管道
    if(mkfifo(argv[1], 0644)==-1)
    {
        perror("mkfifo") ;
        exit(1) ;
    }
    if((fd=open(argv[1],O_WRONLY))==-1)
    {
        perror("open");
        exit(1) ;
    }
    while(1)
    {
        time (&now);
        message=ctime(&now) ;
        if(write (fd, message, strlen(message))==-1)
        {
            perror("write") ;
            exit(1) ;
        }
        sleep(1);
    }
}
// client.c 

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h> 
#include<fcntl.h>
int main(int argc, char *argv[])
{
    int fd, len;
    char buf[128] ;
    if(argc!=2)
    {
        printf("error usage!\nusage: client filename") ;
        exit(1);
    }
    if((fd=open(argv[1],O_RDONLY))==-1)
    {
        perror("open");
        exit(1);
    }
    while((len=read(fd, buf, 128) )>0)
    {
        write(1, buf ,len) ;
    }
    close(fd) ;
}

在这里插入图片描述

4. 共享内存

       共享内存是System V IPC的一种,不依赖于进程的存在而存在。

       以下三种类型的进程通信方式(IPC)合称为System V IPC

  • System V 消息队列
  • System V 信号量
  • System V 共享内存区

       共享内存的通信效率比管道的效率更高。

       共享内存的通信原理图如下所示:

在这里插入图片描述
       共享内存的使用

  1. 创建(shmget
  2. 连接(shmat
  3. 读写(strcpymemcpy
  4. 解开连接(shmdt
  5. 删除(shmctl

       使用共享内存通信调用上方的函数即可实现。

5. 以上三种通信方式的区别

        文件

  • 权限:文件由服务器创建,客户端进程必须具有读文件的权限。.
  • 多个用户:多个客户端程序可以从文件中读取数据。
  • 读写冲突:存在,读写操作需要互斥进行。

        管道

  • 权限:服务器创建管道并写入数据;客户端读取管道中的数据。
  • 多个用户:命名管道是一个内核中的队列,排队首的第-个读进程会将数据取走。
  • 读写冲突: 管道传输数据需要读写双方同时打开管道。多个读进程会排队读取数据;读写进程在管道的不同端,不存在冲突。

        共享内存

  • 权限:共享内存为属主、组用户和其他用户设置了权限,服务器端拥有共享内存,客户端进程要能够读取共享内存。

  • 多用户:多个客户端可以同时从共享内存段中读取数据。

  • 读写冲突:存在。客户端读取数据时,有可能服务器端在写数据,因此需要辅助其他控制手段,保证读写共享内存段互斥进行。

  • 访问速度:

       文件:外存介入
       命名管道:用户态和内核态的转换
       共享内存:外存有可能介入

  • 使用范围:

       命名管道、共享内存:本机上的进程
       文件:不同机器上的进程

6. 信号量

       信号量是一个内存变量,可以被系统中的任何进程所访问。

       多个进程使用信号量来协调对临界资源的访问。

       Linux中信号量是以集合的形式存在的,一个集合中存在着多个信号量。

       信号量的使用:

  1. 创建信号量集(semget
  2. 执行PV操作(semop
  3. 删除信号量集合(semctl

       信号量机制是为了协调多个进程对资源的使用,semop操作对应于操作系统中的PV原语。但与操作系统中的信号量有所不同:

  1. 信号量机制中最小单位是信号量集,并非单个整型数,信号量集中的信号量数目在创建该集合时指定。
  2. 创建信号量集与对其赋初值这两个操作是分开的,并非合在一起的原子操作,这是一个致命的弱点。
  3. 有些程序在终止时并没有释放已经分配给它的信号量集,SEM_ UNDO标识就是用来处理这些情况的。

7. 信号

       信号是内核发送给某一进程的一种消息。

       如一个正在运行的程序,我们按下Ctrl + C就可以终止该程序。

       信号机制Linux系统中用于进程之间相互通信或操作的一种机制。

在这里插入图片描述

8. 消息队列

       消费队列,生产者、消费者的模式。如kafkaRabbitMQ等,一个进程复杂生产消息,另一个进程复杂消费消息。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值