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

通信的本质是传递数据,是相互的。进程之间不能“直接”相互传递数据,因为进程具有独立性,所有的数据操作都会发生写时拷贝,所以一定要通过媒介的方式来传播。
什么是管道?管道是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;
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值