进程间通信——管道和共享内存

1.管道

什么是管道

  • 管道是Unix中最古老的进程间通信的形式。
  • 我们把从一个进程链接到另一个进程的一个数据流称为一个“管道”
  • 管道有:匿名管道和命名管道

1.1 匿名管道

1.1.1匿名管道的创建

匿名管道是一个特殊的文件,在文件IO中创建或打开一个文件用open函数来实现,但是open函数不能创建匿名管道文件,只能用pipe函数来创建

#include<unistd.h>
int pipe(int fd[2]);
功能:创建无名管道文件
参数:fd[2] 有两个成员fd[0]和fd[1],它俩都是文件描述符,
其中fd[0]表示读端,fd[1]表示写端
返回值:成功返回0,失败返会-1

1.1.2 匿名管道实现进程间通信原理

在这里插入图片描述

1.1.3 管道的读写规则

1.如果写端不写入且不关闭文件描述符,读端可能会长时间阻塞。
2.当我们在实际进行写入时,如果写入条件不满足,写入端就要进行阻塞。
3.如果写端关闭文件描述符,读端在读取完文件后会停留在结尾代表结束
4**.如果读端关闭,写端进程会被系统关闭。**

1.1.4 匿名管道的特点

  • 只能用于具有亲缘关系的进程之间通信。
  • 管道是创建在内存中的,进程结束,空间释放,管道就不存在了。(生命周期在进程)
  • 管道中的东西,读完了就删除了
  • 管道是半双工的,数据只能向一个方向流动;要双方通信时,则需要建立两个管道。

1.2 命名管道

1.2.1 命名管道的创建

  • 1.从命令行创建 ————.$ mkfifo filename
  • 2.从程序里创建———— int mkfifo(const char*filename,mode_t mode);
  • 参数:filename 是要创建的管道文件名;mode是创建文件的权限,生成的文件权限是经过mode&(~umask)运算后的结果
  • 返回值:成功返回0,出错返回-1.
  • 注意:mkfifo 是用来创建管道文件的节点,没有在内核中创建管道。只有通过open函数打开这个文件时才会在内核空间创建管道。

1.2.2 用命名管道实现server&client通信

在这里插入图片描述
在这里插入图片描述

//serve.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
  umask(0);
  int mf=mkfifo("fifo",0664);
  if(mf<0)
  {
    perror("mkfifo error\n");
  }
  size_t rf=open("fifo",O_RDONLY);
  if(rf<0)
  {
    perror("open error\n");
  }
  char buf[1024];
  while(1)
  {
    ssize_t rp=read(rf,buf,sizeof(buf)-1);
    if(rp>0){
      buf[rp]=0;
      printf("client say: %s",buf);
    }
    else if(rp==0){
      printf("client quit!\n");
      break;
    }
    else{
      perror("rp error!\n");
    }
  }
  close(rf);
  return 0;
}
//###################################################
//client.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
    int  wf=open("fifo",O_WRONLY);
      if(wf<0){
         perror("wf error!\n");
       }
      char buf[1024];
      while(1)
      {
        printf("please enter:");
        fflush(stdout);
        ssize_t s=read(0,buf,sizeof(buf)-1);
        if(s>0){
          buf[s]=0;
          write(wf,buf,s);
        }
        else{
          perror("read 0 error!\n");
        }
      }
      close(wf);
      return 0;
}

结果展示:
在这里插入图片描述

2. 共享内存

2.1 基本介绍

共享内存在内存中是一块缓存,类似于用户空间的数组或malloc函数分配的空间一样。

2.2 共享内存示意图

在这里插入图片描述

2.3 相关函数介绍

2.3.1 shmget函数

功能:用来创建共享内存
原型:int shmget(key_t key, size_t size, int shmflg);
参数:
key为IPC_PRIVATE或ftok的返回值;
size:共享内存大小;
shmflg:权限位和打开方式。
返回值:
成功返回一个非负整数,即该共享内存段的标识符,即IPC的ID号,出错返回-1.

2.3.1.1 ftok 函数

函数形式:key_t ftok(const char *pathname,int proj_id);
功能: 创建非0的key值。
参数: pathname 路径加文件名,proj_id非0的数。
返回值: 返回一个key,失败返回-1.

2.3.2 shmat 函数

函数形式: void*shmat(int shmid, const void*shmaddr, int shmflg);
功能: 将共享内存段连接到进程地址空间
参数:
shmid 是共享内存的标识
shmaddr:是指定映射到用户空间的首地址,如果shmaddr 被设置为NULL,则映射到用户空间的首地址由系统自动分配;
shmflg: 若是SHM_RDONLY则共享内存为只读,若是0表示共享内存可读可写。
返回值: 成功返回一个指针指向共享内存第一节;失败返回-1.

2.3.3 shmdt 函数

函数形式: int shmdt(const void *shmaddr)
功能:将共享内存段与当前进程脱离
参数:shmaddr:由shmat返回的指针
返回值: 成功返回0,失败-1

2.3.4 shmctl 函数

函数形式:int shmctl (int shmid,int cmd,struct shmid_ds *buf);
功能:删除或查看共享内存
参数:shmid: 是要操作的共享内存标识符
cmd: 三种形式,IPC_STAT 为获取共享内存属性,读取的内容放在参数buf中;IPC_SET 设置共享内存属性,要设置的内容放在buf中;IPC_RMID 为删除共享内存,此时参数buf可能设置为NULL。
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构(属性缓存)。
返回值:成功0,失败-1.
例如:删除共享内存:shmctl(shmid,IPC_RMID,NULL);

补充:命令操作

  • 共享内存查看命令:ipcs -m
  • 共享内存删除命令: ipcrm -m shmid
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值