IPC 进程间通信 interprocess communicate

三大类:

1、古老的通信方式

无名管道 有名管道 信号

2、IPC对象通信 systemvBSD suse fedora kernel.org

消息队列(用的相对少,这里不讨论)

共享内存

信号量集

3、socket通信

网络通信

线程信号,posix sem_init

特列:古老的通信方式中信号是唯一的异步通信

所有的通信方式中共享内存是唯一的最高效

管道==》无名管道、有名管道

无名管道 ===》pipe ==》只能给有亲缘关系进程通信

有名管道===》fifo==》可以给任意单机进程通信

无名管道

1、管道是半双工的工作模式

2、所有的管道都是特殊的文件不支持定位操作。Iseek->>fd fseek->>FILE*

3、管道是特殊文件,读写使用文件IO。fgets,fread,fgetc,(这个有缓冲区)

open,read,write,close(首选)

1,读端存在,一直向管道中去写,超过64k,写会阻塞。

2.写端是存在的,读管道,如果管道为空的话,读会阻塞。

3.管道破裂,,读端关闭,写管道。

4.read0,写端关闭,如果管道没有内容,read;

使用框架:

创建管道==》读写管道==》关闭管道

1、无名管道===》管道的特例===>pipe函数

特性:

1.1亲缘关系进程使用

1.2 有固定的读写端

复制代码
流程:
创建并打开管道:pipe函数
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建并打开一个无名管道
参数:pipefd[0]==>无名管道的固定读端

读堵塞

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
   int fd[2]={0};
   int ret = pipe(fd);
   if(-1==ret)
   {
    perror("pipe");
    return 1;
   }
   pid_t pid =fork();
   if(pid>0)
   {
    close(fd[0]);
    char buf[]="hello,child";
    sleep(3);
    write(fd[1], buf,sizeof(buf)+1);

   }else if(pid==0)
   {
    close(fd[1]);
    char buf[50]={0};
    read(fd[0], buf, sizeof(buf));
    printf("child,buf :%s\n",buf);
   }else
   {
    perror("fork");
    return 1;
   }



    return 0;
}

写堵塞:

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


int main(int argc, char *argv[])
{
    int fd[2]={0};
    // create pipe + open pipe 
    int ret = pipe(fd);
    if(-1 == ret)
    {
    
        perror("pipe");
        return 1;
    }

    pid_t pid = fork();
    if(pid>0)
    {//write fd 
        close(fd[0]);
        char buf[1024]={0};
        memset(buf,'a',sizeof(buf));
        int i = 0 ;
        for(i=0;i<65;i++)
        {
            write(fd[1],buf,sizeof(buf));
            printf("i is %d\n",i);
        }
    }
    else if(0==pid)
    {// read only
        close(fd[1]);
        sleep(5);
        char buf[50]={0};
        read(fd[0],buf,sizeof(buf));
        printf("child ,buf:%s\n",buf);
    }
    else 
    {
        perror("fork");
        return 1;
    }
    return 0;
}

注意:管道的创建必须在fork之前

有名管道

有名管道===》fifo==》有文件名称的管道。 文件系统中可见

框架:

创建有名管道==》打开有名管道==》读写管道==》关闭管道==》卸载有名管道

有名管道的打开,会堵塞。

1.创建:mkfifo

cs 复制代码
#include <sys/types.h>
#include <sys/stat.h>
remove0;

int mkfifo(const char *pathname, mode_t mode);
功能:在指定的pathname路径+名称下创建一个权限为
      mode的有名管道文件。
参数:pathname要创建的有名管道路径+名称
     mode 8进制文件权限。
返回值:成功0
       失败-1;

2.打开有名管道 open

cs 复制代码
注意:该函数使用的时候要注意打开方式,
因为管道是半双工模式,所有打开方式直接决定
当前进程的读写方式。
一般只有如下方式:
int fd-read = open("./fifo",O_RDONLY); ==>fd 是固定读端
int fd-write = open("./fifo",O_WRONLY); ==>fd 是固定写端
不能是O_RDWR方式打开文件。
不能有O_CREAT选项,因为创建管道有指定的mkfifo函数

3、管道的读写:文件IO

cs 复制代码
读: read(fd-read,buff,sizeof(buff);
写 : write(fd-write,buff,sizeof(buff);

4、关闭管道:

close(fd)

5、卸载管道:remove()

cs 复制代码
int unlink(const char *pathname);
功能:将指定的pathname管道文件卸载,同时
从文件系统中删除。
参数:ptahtname 要卸载的有名管道
返回值:成功0
失败-1;

进程间通信===》信号通信

应用:异步通信(时间随机)。中断(被更高优先级的进程打断,等其工作完之后再回到本程序)。

1~64;32应用编程。

信号处理,忽略9和19.

共享内存

IPC对象操作通用框架:

Ox ftok

key值 ==>申请 ==》读写 ==》关闭 ==》卸载

key值:===》唯一键值

创建方式有三种:

1、IPC_PRIVATE固定的私有键值,其值等于 OxO,一般用于有亲缘关系的进程间使用。

2、ftok(创建临时键值。

复制代码
#include <sys/types.h>
#include <sys/ipc.h>
"/etc"!
key_t ftok(const char *pathname, int proj_id);
功能:通过该函数可以将pathname指定的路径用来以
proj_id生成唯一的临时键值。
参数:pathname 路径+名称===》任意文件,只要不会
被删除重建即可。
proj_id 整形的数字,一般用ASCll码的单字符
表示与参数1的运算。
返回值:成功返回唯一键值
失败-1;

ipcs :进程间通信命令显示

ipcrm:进程间通信的删除

eg:

写:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
  key_t key = ftok("./", '!');
  if (-1 == key)
  {
    perror("ftok");
    return 1;
  }
  printf("key is 0x%x\n", key);

  int shmid = shmget(key, 4096, IPC_CREAT | 0666);
  if (-1 == shmid)
  {
    perror("shmid");
    return 1;
  }

  void *p = shmat(shmid, NULL, !SHM_RDONLY);
  if ((void *)-1 == p)
  {
    perror("shmat");
    return 1;
  }
  char buf[] = "hello,this is shm test";
  // strcpy(p,buf);
  memcpy(p, buf, strlen(buf));
  shmdt(p);

  return 0;
}

读:

cs 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
  key_t key = ftok("./", '!');
  if (-1 == key)
  {
    perror("ftok");
    return 1;
  }
  printf("key is 0x%x\n", key);

  int shmid = shmget(key, 4096, IPC_CREAT | 0666);
  if (-1 == shmid)
  {
    perror("shmid");
    return 1;
  }

  void *p = shmat(shmid, NULL, !SHM_RDONLY);
  if ((void *)-1 == p)
  {
    perror("shmat");
    return 1;
  }
  char buf[4096] = {0};
  // strcpy(p,buf);
  memcpy(buf, p, sizeof(buf));
  printf("buf %s\n", buf);
  shmdt(p);
 // shmctl(shmid, IPC_RMID, NULL);
  return 0;
}
相关推荐
羚羊角uou5 小时前
【Linux】模拟实现Shell(下)
linux·运维·服务器
倔强的石头_5 小时前
【Linux指南】Linux调试利器gdb入门:从编译到基础命令实战
linux
CZZDg6 小时前
kubectl-etcd
linux·数据库·etcd
倔强的石头_6 小时前
【Linux指南】gdb进阶技巧:断点高级玩法与变量跟踪实战
linux
半桔6 小时前
【Linux手册】Unix/Linux 信号:原理、触发与响应机制实战
linux·运维·unix·信号处理
半梦半醒*6 小时前
ansible常用命令的简单练习
linux·运维·服务器·ansible·运维开发
atomLg7 小时前
42-Ansible-Inventory
运维·服务器·ansible
小晶晶京京7 小时前
day42-Ansible
linux·运维·服务器·ansible
长河_讲_ITIL47 小时前
预告:AI赋能IT服务管理实践 |2025 “数字化时代的IT服务管理“Meetup-深圳站(9月20日)
大数据·运维·人工智能·itil·itil认证·itil培训