进程间通信--管道

匿名管道

匿名管道只能使有亲缘关系的进程通信

01.利用匿名管道从键盘获取数据显示到屏幕

//匿名管道

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

//创建一个匿名管道 fd:文件描述符数组  fd[0]:读端  fd[1]:写端
//成功返回 0 , 失败返回错误代码
int pipe(int fd[2]);

//创建一个匿名管道, 从键盘写入数据到管道, 从管道读取数据, 显示到屏幕
int main()
{
    int fds[2];
    char buf[1024];
    int len = 0;

    if(pipe(fds) != 0)
    {
        perror("pipe");
        return -1;
    }

    //从键盘读数据
    //char *fgets(char *buf, int bufsize, FILE *stream);
    //参数
    //*buf: 字符型指针,指向用来存储所得数据的地址。
    //bufsize: 整型数据,指明存储数据的大小。
    //*stream: 文件结构体指针,将要读取的文件流。
    while(fgets(buf, 1024, stdin) != NULL)
    {
        len = strlen(buf);
        //数据写入管道
        //ssize_t write(int fd, const void *buf, size_t nbyte);
        //fd:文件描述符;
        //buf:指定的缓冲区,即指针,指向一段内存单元;
        //nbyte:要写入文件指定的字节数;
        //返回值:写入文档的字节数(成功);-1(出错)
        if(write(fds[1], buf, len) < 0)
        {
            perror("write");
            break;
        }
        //清空buf
        //void *memset(void *s, int ch, size_t n);
        //函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
        //memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
        memset(buf, 0x00, sizeof(buf));

        //从管道读取数据
        //函数名: read
        //功 能: 从文件中读
        //用 法: int read(int handle, void *buf, int nbyte);
        if(read(fds[0], buf, 1024) < 0)
        {
            perror("read");
            return -1;
        }

        len = strlen(buf);

        //写到屏幕上
        if(write(1, buf, len) < 0)
        {
            perror("write");
            return -1;
        }
    }
}
02.利用匿名管道实现父子进程间的通信

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

//父子进程通过匿名管道进行通信

//错误处理
#define ERR_EXIT(m)     \ 
do                      \ 
{                       \ 
    perror(m);          \
    exit(EXIT_FAILURE); \
}while(0);

int main(int agrc, char argv[])
{
    int fds[2];
    //创建匿名管道
    if(pipe(fds) != 0)
    {
        ERR_EXIT("pipe error");
        return -1;
    }

    //创建子进程
    pid_t pid = fork();
    if(pid == -1)
    {
        ERR_EXIT("fork error");
        return -1;
    }

    //子进程
    if(pid == 0)
    {
        //关闭子进程的读端
        close(fds[0]);
        //往写端写入hello
        if(write(fds[1], "hello", 5) == -1)
        {
            ERR_EXIT("write error");
            return -1;
        }
        close(fds[1]);
    }

    //父进程
    //关闭父进程的写端
    close(fds[1]);
    char buf[10] = {0};
    //从读端读入到buf
    if(read(fds[0], buf, 5) > 0)
    {
        printf("buf = %s\n", buf);
    }
    return 0;
}
命名管道

如果想实现在两个毫不相干的进程间通信,就可以使用命名管道

01.使用命名管道实现文件赋值

src.h


//命名管道, 可用于不相关的进程间通信
//表头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
//定义函数
//int mkfifo(const char* pathname,mode_t mode);
//若成功则返回0,否则返回-1,错误原因存于errno中

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


//用命名管道实现文件拷贝
//把数据从abc文件写入管道

int main()
{
    //创建一个名为 tmp 的命名管道, 权限664
    mkfifo("tmp", 0664);
    //以只读方式打开 abc 文件
    int in_fd = open("abc", O_RDONLY);
    if(in_fd == -1)
    {
        ERR_EXIT("open error");
    }

    //以读写方式打开 tmp 管道文件
    int out_fd = open("tmp", O_WRONLY);
    if(out_fd == -1)
    {
        ERR_EXIT("open error");
    }

    char buf[1024] = {0};
    int len = 0;

    //从in_fd读数据到buf
    if((len = read(in_fd, buf, 1024)) > 0)
    {
        //从buf写数据到out_fd
        write(out_fd, buf, len);
    }

    close(in_fd);
    close(out_fd);

    return 0;
}

dst.h


//命名管道, 可用于不相关的进程间通信
//表头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
//定义函数
//int mkfifo(const char* pathname,mode_t mode);
//若成功则返回0,否则返回-1,错误原因存于errno中

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


//用命名管道实现文件拷贝
//把数据从tmp文件写入abc_cp

int main()
{
    int out_fd = open("abc_cp", O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if(out_fd == -1)
    {
        ERR_EXIT("open error");
    }

    int in_fd = open("tmp", O_RDONLY);
    if(in_fd == -1)
    {
        ERR_EXIT("open error");
    }

    char buf[1024] = {0};
    int len = 0;

    if((len = read(in_fd, buf, 1024)) > 0)
    {
        //从buf写数据到out_fd
        write(out_fd, buf, len);
    }

    close(in_fd);
    close(out_fd);
    unlink("tmp");
    return 0;
}

这里写图片描述
这里写图片描述

02.利用命名管道进行server和client之间的对话

server.c


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

//利用命名管道实现server和client的对话

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

int main()
{
    umask(0);
    //创建 tmp 管道, 权限664
    if ( mkfifo("tmp", 0664) < 0 )
    {
        ERR_EXIT("mkfifo error");
    }

    //只读打开 tmp 管道文件
    int rfd = open("tmp", O_RDONLY);
    if(rfd == -1)
    {
        ERR_EXIT("opne error");
    }

    char buf[1024] = {0};
    while(1)
    {
        buf[0] = 0;
        printf("Please Wait ... \n");

        size_t s = read(rfd, buf, sizeof(buf)-1);
        if(s > 0)
        {
            buf[s-1] = 0;
            printf("client say: %s\n", buf);
        }
        if(s == 0)
        {
            printf("client quit, me too \n");
            exit(EXIT_SUCCESS);
        }
        if(s < 0)
        {
            ERR_EXIT("read error");
        }
    }

    close(rfd);
    return 0;
}

client.c


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

//利用命名管道实现server和client的对话

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

int main()
{
    //读写打开 tmp 管道文件
    int wfd = open("tmp", O_WRONLY);
    if(wfd < 0)
    {
        ERR_EXIT("opne error");
    }

    char buf[1024] = {0};
    while(1)
    {
        buf[0] = 0;
        printf("I say: ");
        fflush(stdout);

        size_t s = read(0, buf, sizeof(buf)-1);
        if(s > 0)
        {
            buf[s] = 0;
            write(wfd, buf, sizeof(buf)-1);
        }
        if(s <= 0)
        {
            ERR_EXIT("read error");
        }
    }

    close(wfd);
    return 0;
}

这里写图片描述
这里写图片描述

  • 管道提供流式服务
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程
  • 内核会对管道操作进行同步与互斥
  • 管道是半双工的,数据只能向一个方向流动;需要双方互相通信时,需要建立起两个管道
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值