管道

一、无名管道 

1. 什么是管道

一个管道实际上就是个只存在内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端。管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构,类似时空隧道的概念,建立两个进程之间的通讯桥梁,数据的读出和写入:一个进程向管道写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

2. 无名管道的特性

  • 只能用于具有亲缘关系的进程之间的通信,通常一个管道由一个进程创建,然后该进程调用fork,此后父子进程之间就可以通过管道通信。
  • 半双工的通信模式

 

int pipe(int fd[2]);

调用pipe函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端,一个写端,然后通过fd参数传出给用户程序两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。所以管道在用户程序看起来就像一个打开的文件,通过read(fd[0])或者write(fd[1])向这个文件读写数据,其实是读写内核缓冲区。

 

注意:

输出结果:

 1. 测试代码:

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

int main()
{
    int fd[2] = {};
    pipe(fd); //创建0两个管道,fd[0] 读, fd[1] 写
        pid_t pid = fork();
    if (pid == 0) { //子进程
        close(fd[1]);  //关闭写端
        int i;
        for (i = 0; i < 100; i++) {
            int x;
            read(fd[0], &x, 4);
            printf("%d ", x);
            fflush(0);
        }
        close(fd[0]);
        exit(0);
    }
    close(fd[0]);
    int i;
    for(i = 100; i < 200; i++) {
        write(fd[1], &i, 4);
        usleep(100000); //0.1秒
    }
    close(fd[1]);
    return 0;
}

输出结果:


2. 测试代码:

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


int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe error");
        exit(-1);
    }
    pid_t pid;
    pid = fork();
    if (pid == -1) {
        perror("fork error");
        exit(-1);
    }
    if (pid == 0) {   //写
        dup2(pipefd[1], STDOUT_FILENO);
        close(pipefd[1]);
        close(pipefd[0]);
        execlp("ls", "ls", NULL);
        fprintf(stderr, "error excute ls\n");
        exit(EXIT_FAILURE);
    }
    dup2(pipefd[0], STDIN_FILENO);  //读
    close(pipefd[1]);
    close(pipefd[0]);
    execlp("wc", "wc", "-w", NULL);
    fprintf(stderr, "error excute wc\n");
    exit(EXIT_FAILURE);    
}

 输出结果:


2. 测试代码:

#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    close(0);
    open("test.txt", O_RDONLY);
    close(1);
    open("test2.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    execlp("cat", "cat", NULL);
    return 0;
}

 输出结果:

 

管道的读写规则 

1. 当没有数据可读时:

  • O_NONBLOCK  disable:read调用阻塞,即进程暂停执行,一直等到有数据来到位置。
  • O_NONBLOCK  enable:read调用返回-1,errno值为EAGAIN。

2. 如果所有管道写端对应的文件描述符被关闭,则read返回0

3. 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE。

4. 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

5. 当要写入的数据量大于PIPE_BUF时,linux将不再写入的原子性。

1. 测试代码:

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

int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if (pid == -1) {
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        sleep(3);
        close(pipefd[0]);
        write(pipefd[1], "hello", 5);
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }
    close(pipefd[1]);
    char buf[10] = { 0 };
    read(pipefd[0], buf, 10);
    printf("buf = %s\n", buf);
    return 0;
}

输出结果:


2. 测试代码:

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

int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if (pid == -1) {
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        sleep(3);
        close(pipefd[0]);
        write(pipefd[1], "hello", 5);
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }
    close(pipefd[1]);
    char buf[10] = { 0 };
    int flags = fcntl(pipefd[0], F_GETFL);
    fcntl(pipefd[0], F_SETFL, flags | O_NONBLOCK);
    int ret = read(pipefd[0], buf, 10);
    if (ret == -1) {
        perror("read error");
        exit(EXIT_FAILURE);
    }
    printf("buf = %s\n", buf);
    return 0;
}

输出结果:


 

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

int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if (pid == -1) {
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }
    close(pipefd[1]);
    sleep(1);
    char buf[10] = { 0 };
    int ret = read(pipefd[0], buf, 10);
    printf("ret = %d\n", ret);
    return 0;        
}

输出结果:


测试代码:

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

void handler(int sig)
{
    printf("recv a sig = %d\n", sig);
}

int main(int argc, char *argv[])
{
    signal(SIGPIPE, handler);
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if (pid == -1) {
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    }
    close(pipefd[0]);
    sleep(1);
    char buf[10] = { 0 };
    int ret = write(pipefd[1], "hello", 5);
    if (ret == -1) {
        printf("write error\n");
    }
    return 0;
}

 输出结果:


3. 测试代码:

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

int main(int argc, char *argv[])
{
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    int ret;
    int  count = 0;
    int flags = fcntl(pipefd[1], F_GETFL);
    fcntl(pipefd[1], F_SETFL, flags | O_NONBLOCK);
    while (1) {
        ret = write(pipefd[1], "A", 1);
        if (ret == -1) {
            printf("err = %s\n", strerror(errno));
            break;
        }           
        count++;
    }
    printf("count = %d\n", count);
    return 0;
}

输出结果:


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值