Linux中管道-学习笔记(六)

1、匿名管道
(1)确定通信方向:
1)父写子读,关闭父读,关闭子写
  2)子写父读,关闭子读,关闭父写
(2)好处:确定,经典
(3)注意事项:
1)写端关闭,读端仍然在读,则读完管道中的内容后再次读时,读到EOF,返回0。
2)写端未写完数据,写端暂无数据但未关闭,则读端将数据读完,再次去读时,发生阻塞。
3)读端关闭,写端写数据到管道,进程产生SIGPIPE信号,默认写进程会终止进程
4)写端数据写满了,读端未将数据读完,再次写时,发生阻塞

//程序1 匿名管道
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    int fd[2];//定义文件描述符
    pid_t pid;//定义进程
    char str[1024]="hello,myworld";
    char buf[1024];
    //开辟管道
    if(pipe(fd)<0)
    {
        perror("pipe");
        exit(1);
    }
    pid=fork();//创建父进程和子进程
    //确定方向,父写子读
    if(pid>0)  //父进程,关闭父读
    {
        close(fd[0]);
        write(fd[1],str,strlen(str));//写数据到文件
        wait(NULL);
    }
    else if(pid==0)//子进程,关闭子写
    {
        int len;//读取到的数据字节数
        close(fd[1]);
        memset(buf,0,sizeof(buf));//清空缓存数组
        len=read(fd[0],buf,sizeof(buf));//从写端读取数据
        write(STDOUT_FILENO,buf,len);//将数据显示到终端
        printf("\n");//读取完毕
    }
    else  //创建进程失败
    {
        perror("fork\n");
        exit(-1);
    }
}
程序运行效果:

//程序2 匿名管道-非阻塞读管道文件
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

int main(void)
{
    int fd[2];
    pid_t pid;
    char str[1024]="hello,myworld";
    char buf[1024];
    
    if(pipe(fd)<0)
    {
        perror("pipe");
        exit(1);
    }
    pid=fork();//创建父进程和子进程
    //确定方向,父写子读
    if(pid>0) //父进程,关闭父读
    {
        close(fd[0]);
        write(fd[1],str,strlen(str));//写数据到文件
        wait(NULL);
    }
    else if(pid==0) //子进程,关闭子写
    {
        int len,flags;
        close(fd[1]);
        //先读后写
        flags=fcntl(fd[0], F_GETFL);//非阻塞读终端
        flags |= O_NONBLOCK;//非阻塞读终端
        flags =fcntl(fd[0],F_SETFL,flags); //改变fd[0]的属性
        
        memset(buf,0,sizeof(buf));//清空缓存数组
        while(1)
        {
            len=read(fd[0],buf,sizeof(buf));//从写端读取数据
            write(STDOUT_FILENO,buf,len);//将数据显示到终端
            if(len>0)//读取到数据
            {
                break;
            }
        }
        printf("\n");
    }
    else  //创建进程失败
    {
        perror("fork\n");
        exit(-1);
    }
}

程序运行效果:

 

2、fifo有名管道--解决无血缘关系的进程通信
管道文件myfifo存放在磁盘中,标记为内核中的一条管道,管道文件只是一个文件名,没有真正大小
创建管道文件:
[root@localhost 808]# mkfifo xwp
[root@localhost 808]# ls -l xwp   //查看管道文件信息
prw-r--r-- 1 root root 0 07-31 04:26 xwp
prw--代表管道文件

 

//程序3 有名管道 写文件
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
    //通过文件的控制属性,访问管道文件
    int fd;//定义文件描述符
    char buf[1024]="hello everybody\n";
    
    if(argc<2)//判断是否有输入
    {
        printf("enter your fifoname\n");
        exit(1);
    }
    fd=open(argv[1],O_WRONLY);//只写方式打开文件
    if(fd<0)
    {
        perror("open\n");
    }
    write(fd,buf,strlen(buf));//将数据写到终端并显示出来
    close(fd);//关闭文件
    return 0;
}
//程序4、有名管道 读文件
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
    //通过文件的控制属性,访问管道文件
    int fd;//定义文件描述符
    int len;//读取数据字节数
    char buf[1024];//读取数据缓存区
    if(argc<2)//判断是否有输入
    {
        printf("enter your fifoname\n");
        exit(1);
    }
    fd=open(argv[1],O_RDONLY);//只读方式打开文件
    if(fd<0)
    {
        perror("open\n");
    }
    memset(buf,0,sizeof(buf));//清空缓冲区
    len=read(fd,buf,sizeof(buf));//从文件读取数据
    write(STDOUT_FILENO,buf,len);//将数据写到终端并显示出来
    close(fd);//关闭文件
    return 0;
}
程序3和程序4结合使用,程序运行效果:

 

3、复制文件描述符dup、dup2
//程序5 复制文件描述符dup
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    int fd;//定义文件描述符
    int newfd;//定义新文件描述符
    fd=open("filea.c",O_RDWR | O_CREAT,0777);//只写方式打开文件
    printf("fd=%d\n",fd);//输出文件描述符
    if(fd<0)
    {
        perror("open\n");
    }
    //复制文件描述符,实质指向fd "abc" file*,所以操作newfd和操作fd是一样的
    newfd=dup(fd);
    printf("newfd=%d\n",newfd);//输出文件描述符
    write(newfd,"hello",5);//写数据到新文件描述符所指的文件
    close(fd);//关闭文件
    close(newfd);//关闭文件
    return 0;
}
程序执行效果:

 

//程序6 文件描述符重定向
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
    int fd,newfd;//定义文件描述符
    //读写或创造方式打开文件
    fd=open("fileb.c",O_RDWR | O_CREAT,0777);
    printf("fd=%d\n",fd);//输出文件描述符
    if(fd<0)
    {
        perror("open\n");
    }
    //重定向,跟dup区别,可以用newfd来指定新的文件描述符的值
    //若文件已经被打开,先关闭,如果重定向文件等于原来的fd,则共用一份文件
    newfd=dup2(fd,5);//重定向后依然向fd所指文件写入数据
    printf("newfd=%d\n",newfd);//输出新文件描述符值
    write(newfd,"hello",5);//向新文件写入数据
    
    close(fd);//关闭文件
    close(newfd);//关闭文件
    return 0;
}



程序执行效果:

 

扩展:
使用命名管道创建一个FileTP的管道文件,使用该管道实现S.out到R.out的文件内容的传送。
//程序7 将数据从文件1写入管道文件
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
    //通过文件的控制属性,访问管道文件
    int fd,newfd;//定义文件描述符
    char str[1024]="hello everybody\n";
    char buf[1024];
    int len;
    
    //创建或打开一个文件
    fd=open("file1.h",O_CREAT | O_RDWR,0644);
    write(fd,str,strlen(str));//将数据写入文件
    close(fd);//关闭文件
    fd=open("file1.h",O_RDWR);//再次打开文件
    //阻塞读
    printf("fd=%d\n",fd);//输出文件描述符
    printf("lensizeof(buf)=%d\n",sizeof(buf));//计算字符数组大小
    memset(buf,0,sizeof(buf));//清空缓存区
    len=read(fd,buf,sizeof(buf));//从文件1中读取数据并存放到缓存数组中
    if(argc<2)//判断是否有输入
    {
        printf("enter your fifoname\n");
        exit(1);
    }
    newfd=open(argv[1],O_WRONLY);//只写方式打开文件
    if(newfd<0)
    {
        perror("open\n");
    }
    write(newfd,buf,strlen(buf));//将数据写到管道文件中
    close(newfd);//关闭管道文件
    close(fd);//关闭文件1
    
    return 0;
}


//程序8 将数据从管道文件写入文件2中
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
    //通过文件的控制属性,访问管道文件
    int fd,newfd;
    int len;
    char buf[1024];
    if(argc<2)//判断是否有输入
    {
        printf("enter your fifoname\n");
        exit(1);
    }
    fd=open(argv[1],O_RDONLY);//只读方式打开文件
    if(fd<0)
    {
        perror("open\n");
    }
    memset(buf,0,sizeof(buf));//清空缓冲区
    len=read(fd,buf,sizeof(buf));//从管道文件中读取数据
    write(STDOUT_FILENO,buf,len);//将数据写到终端并显示出来
    //创建或打开一个文件
    newfd=open("file2.h",O_CREAT | O_RDWR,0644);
    write(newfd,buf,strlen(buf));//将数据写入文件2中
    close(newfd);//关闭文件2
    close(fd);//关闭管道文件
    return 0;
}


程序7和程序8结合使用,程序执行效果:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值