0
点赞
收藏
分享

微信扫一扫

Linux基础 ——“进程间通信” 沟通是怎么连接的呢

杰克逊爱学习 2022-03-25 阅读 117

文章目录

进程间通信(IPC)篇

一、进程间通信概述

进程间通信是指在不同进程之间传播或交换信息,IPC的方式常有管道(包括无名管道和命名管道)消息队列,信号量,共享存储,Socket,Stream等。其中Socket和Stream支持不同主机上的两个进程IPC。
在这里插入图片描述
在这里插入图片描述

单机通信多机通信
半双工管道(FIFO)套接字
全双工管道STPEAMS
消息队列
信号量
共享存储

二、管道通信原理

1. 管道(无名管道):

管道,通常指 无名管道 ,是UNIX系统IPC最古老的形式。只存在于内存中,当父子进程退出后,管道就消失了。

1.特点:

  1. 它是 半双工 的(即数据只能在一个方向上流动),具有固定的读端和写端。在这里插入图片描述

  2. 它只是用于具有 亲缘关系 的进程之间 通信(也是父子进程或者兄弟进程之间)

  3. 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read,write等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且 只存在于内存中 。当父子进程退出后,管道就消失了。

2.原型:

#include<unistd.h>
int pipe(int fd[2]);    //返回值 :若成功返回0   失败返回-1

3.返回值: 若成功返回0 失败返回-1

当一个管道建立时候,它会创建两个文件描述符: fd[0] 为读而打开fd[1] 为写而打开。

read(fd[0] , buff , 128);
write(fd[1] , “hello world \n” , 12);

在这里插入图片描述

要关闭管道,只需要将这两个文件描述符关闭即可。

close(fd[0]); //关闭读端
close(fd[1]); //关闭写端

例如:单个进程中的管道几乎没有任何用处。所以,通常调用pipe的进程接着调用fork,这样就创建了父进程与子进程之间的IPC通道,
在这里插入图片描述

2. 管道 编程的实战:

无名管道:父进程往管道里写,子进程从管道外读:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>


int main()
{
     int fd [2];  //两个文件描述符
     pid_t pid;
     char buff [128];
      if(pipe(fd) == -1){   //创建管道
            printf("Create pipe error! \n");    //创建管道错误    
       }
       pid = fork;       //创建子进程
       if(pid<0){  
             printf("Fork  error  \n");    //fork错误
       }else  if(pid > 0{   //父进程
                wait();
                printf("this is father\n");
                close(fd[0]);    //关闭读端
                 write(fd[1],"hello world \n",12);         
       }else{
                 printf("this is child\n");
                 close(fd[1]);    //关闭写端
                 read(fd[0],buff,128);
                 printf("read from father:%s\n",buff);
                 exit(0);
        }
         return 0;
}

若read 没读到数据 ,read会阻塞

三、FIFO (命名管道)

FIFO,也称为命名管道,它是一种文件类型。

1.特点:

  1. FIFO可以在无关的进程之间交换数据,与无名管道不同。

  2. FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。

2.原型:

#include<sys/stat.h>
#include<sys/types.h>
//返回值:成功返回0 ,失败返回-1
int mkfifo(char *pathname , mode_t mode);

返回值:成功返回0 ,失败返回-1

参数说明:
mode与open函数中的mode相同。一旦创建一个FIFO,就可以用一般的文件I/O函数操作它(如 open ,read ,write)。

1. 创建FIFO有名管道代码:

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>

// int mkfifo(const char *pathname ,mode_t mode);

int main(){
      if((mkfifo("./file",0600)== -1)&& errno!=EEXIST){
              printf("mkfifo failuer\n");
              perror("why");
      }
      return 0;
}

在这里插入图片描述
管道读取:

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
#include<fcntl.h>
// int mkfifo(const char *pathname ,mode_t mode);

int main(){
      if((mkfifo("./file",0600)== -1)&& errno!=EEXIST){
              printf("mkfifo failuer\n");
              perror("why");
      }


      int fd = open("./file",O_RDONLY);     //O_RDONLY读数据
      printf("open success\n");

      return 0;
}

结果显示:
创建一个管道后, 打开管道后printf(“open success\n”); 没有执行。
在这里插入图片描述

2. 当open一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别?

  • 没有指定O_NONBLOCK(默认)只读open要阻塞 到某个 其他进程为写而打开此FIFO ,类似的,只写open要阻塞到某个其他他进程为读而打开它。

  • 指定了O_NOBLOCK,则只读open立即返回。而只写open将出错误返回-1 如果没有进程已经为读而打开该FIFO,其errno置ENXIO

所以说上面代码是用写的方式打开管道,就不会堵塞了

3. 命名管道的数据通信编程实现:

写的当时打开管道:
./read

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
#include<fcntl.h>
// int mkfifo(const char *pathname ,mode_t mode);
int main(){

      int buf[30]={0};

      if((mkfifo("./file",0600)== -1)&& errno!=EEXIST){   //创建管道
              printf("mkfifo failuer\n");
              perror("why");
      }

      int fd = open("./file",O_RDONLY);   //O_RDONLY 读数据
      printf("write open success\n");
      int nread = read(fd,buf,30);
      printf("read%d byte from fifo context:%s\n",nread,buf);
      return 0;
}

./write

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
#include<fcntl.h>

int main(){

      int fd = open("./file",O_WRONLY); //O_WRONLY 写数据
      printf("write open success\n");
      return 0;
}

当用读的方式打开 会堵塞, 只写open要阻塞到某个其他他进程为读而打开它。
在./read堵塞的时候,在执行./write ,就可以获取数据
在这里插入图片描述
也可以实现两个进程间通信:多次写入:
./read

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<errno.h>
#include<fcntl.h>

int main(){

      int buf[30]={0};
      int nread=0;

      int fd = open("./file",O_RDONLY);
      printf("write open success\n");

      while(1){
         nread = read(fd,buf,30);
         printf("read%d byte from fifo context:%s\n",nread,buf); 
         } 
      return 0;
}

./write

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

int main(){

      int cnt=0;
      char *str="message from fifo";

      int fd = open("./file",O_WRONLY);
      printf("write open success\n");
      while(1){
      write(fd,str,strlen(str));
      sleep(1);
        if(cnt == 5){
             break;
        }
      }
      return 0;
}

在这里插入图片描述

举报

相关推荐

0 条评论