进程通信--匿名管道和命名管道

Posted 你快看看我

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程通信--匿名管道和命名管道相关的知识,希望对你有一定的参考价值。

通信的本质是传递数据,是相互的。进程之间不能“直接”相互传递数据,因为进程具有独立性,所有的数据操作都会发生写时拷贝,所以一定要通过媒介的方式来传播。
什么是管道?管道是Unix最古老的进程间通信的形式,我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。

一.匿名管道

供具有血缘关系的进程进行进程间通信,常见于父子进程。
1.父进程创建管道
以读方式打开一次,以写方式打开一次,文件描述符3,4就会指向同一个文件

2.父进程fork出子进程
子进程写时拷贝父进程

3.父进程关闭fd[0],子进程关闭fd[1]
父子进程各自关闭不需要的文件描述符,来达到构建单向通信的信道目的,父进程写入,子进程读取
为什么曾经读写端都要打开?因为不打开rw,子进程拿到的文件打开方式必定和父进程一样,两个都是r或者两个都是w,无法通信;父进程w子进程r或者子进程w父进程r更加灵活。
为什么一定要关闭呢?因为放置误操作。
管道为什么只能单向通信呢?因为读写位只有一个。

例子:从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main( void )

    int fds[2];
    char buf[100];
    int len;
    
    if ( pipe(fds) == -1 )
        perror("make pipe"),exit(1);
    // read from stdin
    while ( fgets(buf, 100, stdin) ) 
        len = strlen(buf);
        // write into pipe
        if ( write(fds[1], buf, len) != len ) 
             perror("write to pipe");
             break;
        
        memset(buf, 0x00, sizeof(buf));
        
        // read from pipe
        if ( (len=read(fds[0], buf, 100)) == -1 ) 
            perror("read from pipe");
            break;
        
        
       // write to stdout
       if ( write(1, buf, len) != len ) 
           perror("write to stdout");
           break;
        
    
 

二.匿名管道的特性

如果管道里面没有消息,父进程(读端)就会等待,等子进程写入,管道内部有数据就绪;如果管道里面写端已经写满了,不能继续写了,等待父进程读取,管道内部有空闲空间;如果读端在读,但是写端不写并且关闭,读端读取到0,文件结束;如果读端不读,而且读端关闭,一直写毫无意义,一直写本质就是在浪费系统资源,写进程会立马被OS终止掉,此时写进是子进程,通过发送信号的方式
(1)管道自带同步机制
(2)管道是单向通信的
(3)管道是面向字节流的
(4)管道只能保证是具有血缘关系的进程通信,常用于父子
(5)管道可以保证一定程度的数据读取的原子性
(6)进程退出,曾经打开的文件也会被关掉,管道也是文件,管道的声明周期是随进程的

三.命名管道

管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件
命名管道可以从命令行上创建,命令行方法是使用下面这个命令:$ mkfifo filename
命名管道也可以从程序里创建,相关函数有:int mkfifo(const char *filename,mode_t mode);
创建命名管道:

int main(int argc, char *argv[])

 mkfifo("p2", 0644);
 return 0;

匿名管道和命名管道的区别:
(1)匿名管道由pipe函数创建并打开。
(2)命名管道由mkfifo函数创建,打开用open
(3)FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

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

# ll
total 12
-rw-r--r--. 1 root root 46 Sep 18 22:37 clientPipe.c
-rw-r--r--. 1 root root 164 Sep 18 22:37 Makefile
-rw-r--r--. 1 root root 46 Sep 18 22:38 serverPipe.c

# cat Makefile
.PHONY:all
all:clientPipe serverPipe
serverPipe.c
clientPipe:clientPipe.c
     gcc -o $@ $^
serverPipe:serverPipe.c
     gcc -o $@ $^
 
.PHONY:clean
clean:
     rm -f clientPipe serverPipe

serverPipe.c

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

#define ERR_EXIT(m) \\
do\\
    perror(m);\\
    exit(EXIT_FAILURE);\\
while(0)

int main()

    umask(0);
    if(mkfifo("mypipe", 0644) < 0)
        ERR_EXIT("mkfifo");
    
    int rfd = open("mypipe", O_RDONLY);
    if(rfd < 0)
         ERR_EXIT("open");
    
    
    char buf[1024];
    while(1)
        buf[0] = 0;
        printf("Please wait...\\n");
        ssize_t s = read(rfd, buf, sizeof(buf)-1);
        if(s > 0 )
             buf[s-1] = 0;
             printf("client say# %s\\n", buf);
        else if(s == 0)
            printf("client quit, exit now!\\n");
            exit(EXIT_SUCCESS);
        else
            ERR_EXIT("read");
        
    
    close(rfd);
    return 0;

clientPipe.c

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

#define ERR_EXIT(m) \\
do\\
   perror(m);\\
   exit(EXIT_FAILURE);\\
while(0)
int main()

    int wfd = open("mypipe", O_WRONLY);
    if(wfd < 0)
         ERR_EXIT("open");
    
    char buf[1024];
    while(1)
          buf[0] = 0;
          printf("Please Enter# ");
          fflush(stdout);
          ssize_t s = read(0, buf, sizeof(buf)-1);
          if(s > 0 )
               buf[s] = 0;
               write(wfd, buf, strlen(buf));
          else if(s <= 0)
                ERR_EXIT("read");
           
   
   close(wfd);
   return 0;

以上是关于进程通信--匿名管道和命名管道的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信:命名管道

进程间通信——命名管道

进程间通信

swoole进程间如何通信

进程通信--匿名管道和命名管道

进程通信--匿名管道和命名管道