进程通信之管道

本文介绍了Linux系统中两种类型的管道通信方式:无名管道和命名管道。无名管道适用于父子进程或兄弟进程间的通信,通过`pipe`函数创建,读写操作可以设置为阻塞或非阻塞。命名管道则可用于非血缘关系进程间通信,通过`mkfifo`函数创建。通过实例展示了如何使用无名管道的`dup`和`dup2`进行文件描述符重定向,以及如何利用命名管道实现单机通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

无名管道

无名管道适用于父子进程或兄弟进程之间的通信

pipe
//pipe(int *fd);
//参数:数组,fd[0]读,fd[1]写
//返回值:成功0,失败-1
//利用无名管道通信往往是父进程创建管道,子进程继承无名管道文件描述符
//read读数据默认阻塞
//write写数据,缓冲区满阻塞
//关闭所有读端,向管道写数据,写进程会收到SIGPIPE信号而退出

//fcntl(fd, F_SETFL, 0/O_NONBLOCK);
//功能:设置阻塞非阻塞
//参数:文件描述符,宏,0/O_NONBLOCK

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



int main(int argc, char *argv[])
{
    pid_t pid;

    int fd_pipe[2] = {0};
    if(pipe(fd_pipe) < 0)
    {
        perror("pipe");
    }
    pid = fork();
    if(pid == -1)
    {
        perror("fork");
        return 0;
    }
    else if(pid == 0)
    {
        char *str = "pipe send helloworld\n";
        write(fd_pipe[1], str, strlen(str));
        _exit(0);
    }
    else if(pid > 0)
    {
        //fcntl(fd_pipe[0], F_SETFL, O_NONBLCOK);//设置读端非阻塞
        //fcntl(fd_pipe[0], F_SETFL, 0);         //设置读端阻塞
        char str[100] = "";
        wait(NULL);//挂起父进程,等待子进程结束或收到信号
        read(fd_pipe[0], str, sizeof(str) - 1);
        printf("无名管道接收消息:%s", str);
    }
    return 0;
}

执行结果:
在这里插入图片描述
dup,dup2
重定向文件描述符

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

//int dup(int oldfd)
//功能:复制一份打开的文件描述符oldfd,返回可用的最小 新的文件描述符


int main(int argc, char *argv[])
{
    int fd, new_fd;

    fd = open("./test.txt", O_RDWR);
    if(fd < 0)
    {
        perror("open");
        return 0;
    }
    close(1);
    new_fd = dup(fd);
    printf("new_fd = %d\n", new_fd);
    printf("hello wrold\n");
    //fflush(stdout);
    write(new_fd, "mine\n", 5);

    return 0;
}
//int dup2(int oldfd, int newfd)


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

// int main(void)
// {
// 	int fd1;
// 	int fd2;
	
// 	fd1 = open("test.txt", O_CREAT | O_WRONLY, 0666);
// 	if (fd1 < 0)
// 	{
// 		perror("open:");
// 		exit(-1);
// 	}
// 	fd2 = dup2(fd1, 1);
// 	printf("fd2=%d\n", fd2);
// 	return 0;
// }

实例

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

int main(int argc, char *argv[])
{
    int fd_pipe[2];
    pid_t pid = 0;
    //创建管道
    int ret = pipe(fd_pipe);
    if(ret < 0)
        perror("pipe");
    pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return 0;
    }
    else if(pid == 0)
    {
        dup2(fd_pipe[1], 1);
        execlp("expr", "expr", "4", "+", "5", NULL);
        _exit(0);
    }
    else if(pid > 0)
    {
        wait(NULL);
        char str[100] = "";
        read(fd_pipe[0], str, sizeof(str) - 1);
        printf("num = %s\n", str);
    }

    return 0;
}

执行结果:
在这里插入图片描述

命名管道

适用于非血缘关系进程间通信
mkfifo
//命名管道:进程间通信
//int mkfifo(char *pathname, int num)
//参数:创建管道文件pathname,规定管道文件权限num
//返回值:成功0,失败非0

writefifo.c

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



int main(int argc, char *argv[])
{
    int fd;
    int ret = mkfifo("fifo", 0666);
    if(ret != 0)
        perror("fifo");
    //以只读打开管道
    fd = open("./fifo", O_WRONLY);
    if(fd <0)
    {
        perror("open");
    }
    printf("write fifo success\n");
    write(fd, "hello fifo\n", 11);

    return 0;
}

readfifo.c

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

//命名管道:进程间通信
//int mkfifo(char *pathname, int num)
//参数:创建管道文件pathname,规定管道文件权限num
////返回值:成功0,失败非0

//以O_NONBLOCK打开特点
//1.先以只读方式打开,open不阻塞
//2.先以只写方式打开:只写open出错返回-1
//3.写进程退出会导致read阻塞不住
//4.读进程结束写进程收到信号结束进程

int main(int argc, char *argv[])
{
    int fd;
    char str[100] = "";
    int ret = mkfifo("fifo", 0666);
    if(ret != 0)
        perror("fifo");
    //以只读打开管道
    fd = open("./fifo", O_RDONLY);
    //以非阻塞方式打开
    //fd = open("./fifo", O_RDONLY | O_NONBLOCK);
    if(fd <0)
    {
        perror("open");
    }
    printf("write fifo success\n");
    read(fd, str, sizeof(str));
    printf("write fifo is %s\n", str);

    return 0;
}

执行结果:
在这里插入图片描述
利用命名管道实现单机通信
readfifo.c

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

//利用命名管道写一个进程通信工具

int main(int argc, char *argv[])
{
    pid_t pid;
    //1.创建管道
    if(mkfifo("b_to_a", 0666) != 0)
        perror("mkfifo");
    
    int fd_write = open("a_to_b", O_WRONLY);
    int fd_read = open("b_to_a", O_RDONLY);
    if(fd_read < 0)
        perror("open read");
    if(fd_write < 0)
        perror("open write");
    
    pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return 0;
    }
    else if(pid == 0)
    {
        while(1)
        {
            char str[100] = "";

            fgets(str, sizeof(str) - 1, stdin);
            str[strlen(str) - 1] = '\0';
            write(fd_write, str, sizeof(str));
        }
    }
    else if(pid > 0)
    {
        while(1)
        {
            char str[100] = "";

            read(fd_read, str, sizeof(str));
            printf("LIU:");
            fflush(stdout);
            printf("%s\n", str);
        }
    }

    return 0;
}

writefifo.c

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

//利用命名管道写一个进程通信工具

int main(int argc, char *argv[])
{
    pid_t pid;
    //1.创建管道
    if(mkfifo("a_to_b", 0666) != 0)
        perror("mkfifo");
    
    int fd_read = open("a_to_b", O_RDONLY);
    int fd_write = open("b_to_a", O_WRONLY);
    if(fd_read < 0)
        perror("open read");
    if(fd_write < 0)
        perror("open write");
    
    pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return 0;
    }
    else if(pid == 0)
    { 
        while(1)
        {
            char str[100] = "";

            fgets(str, sizeof(str) - 1, stdin);
            str[strlen(str) - 1] = '\0';
            write(fd_write, str, sizeof(str));
        }
    }
    else if(pid > 0)
    {
        while(1)
        {
            char str[100] = "";

            read(fd_read, str, sizeof(str));
            printf("LI :");
            fflush(stdout);
            printf("%s\n", str);
        }
    }
    
    return 0;
}

执行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值