设为首页 收藏本站
查看: 539|回复: 0

[经验分享] 在Linux下的进程间通信之匿名管道

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-4-11 09:11:12 | 显示全部楼层 |阅读模式
    每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到。所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2 在从内核缓冲区把数据读走。

  管道是一种最基本的IPC机制,由pipe函数创建:
调用pippe函数时在内核中开辟一块缓冲去(称为管道)用于通信,它有一个读端,一个写端,然后通过fileds参数传出给用户程序两个文件描述符,fileds[0]指向管道的读端,fileds[1]指向管道的写端,所以管道在用户程序看起来就像一个打开的文件,通过read 或者write;向这个文件读写数据实际是在读写内核缓冲区。
管道是实现进程间的通信需要经过以下几步:
1).创建一个管道
2).创建两个进程
3).分别关闭一个进程的读端,另一个的写端
4).实现通信
程序具体如下:
(一)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        int _pipe_fd[2]={-1,-1};
        int _pipe=pipe(_pipe_fd);
        if(_pipe<0){
                perror("pipe");
                exit(1);
        }
        int _pid=fork();
        if(_pid<0){
                perror("fork");
                exit(2);
        }else if(_pid==0){//child
                close(_pipe_fd[0]);
                char buf[1024]="hello world\n";
                fflush(stdout);
                int count =10;
                while(count--){
                    char buf[1024]="hello world\n";
                }

                sleep(5);
        }
        else{//father
                close(_pipe_fd[1]);
                char buf[1024];
                while(1){
                        memset(buf,'\0',sizeof(buf));
                        ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));
                        if(_size<0){
                                perror("read");
                                exit(3);
                        }else{
                                printf("%s",buf);
                        }
                        }
               
                }
        }
        return 0;
}
运行结果为:
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world

因为读端一直循环,一直在读,而写端并没有在写,所以读端最终会阻塞。
(二)如果所有指向管道写端的文件描述符都关闭了,而仍然有进程从管道的读端读数据,那么管道剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        int _pipe_fd[2]={-1,-1};
        int _pipe=pipe(_pipe_fd);
        if(_pipe<0){
                perror("pipe");
                exit(1);
        }

        int _pid=fork();
        if(_pid<0){
                perror("fork");
                exit(2);
        }else if(_pid==0){//child
                close(_pipe_fd[0]);
                //char buf[1024]="hello world\n";
                //fflush(stdout);
                int count =10;
                while(count--){
                    char buf[1024]="hello world\n";
                    write(_pipe_fd[1],buf,strlen(buf));
                    sleep(2);
                }
                close(_pipe_fd[1]);
        }
        else{//father
                close(_pipe_fd[1]);
                char buf[1024];
                int j=0;
                while(j++ < 15){
                        memset(buf,'\0',sizeof(buf));
                        ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));
                        if(_size<0){
                                perror("read");
                                exit(3);
                        }else{
                                printf("%s",buf);
                        }
                    }
                    int status=0;
                    if(waitpid(_pid, &status,0)==_pid){
                                printf("wait sucess,sigcode\n:%d",status & 0xFF);
                                break;
                        }
        }
        return 0;
}
程序运行结果为:
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
wait sucess,sigcode:0
(三)
如果有指向管道写端的文件描述符没关闭,而持有管道写端的进程也没有向管道写数据,这时有进程从管道读端读数据,那么管道中剩余的数据被读取后,再次read会被阻塞,直到管道中有数据可读了才读取数据并返回。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        int _pipe_fd[2]={-1,-1};
        int _pipe=pipe(_pipe_fd);
        if(_pipe<0){
                perror("pipe");
                exit(1);
        }
        int _pid=fork();
        if(_pid<0){
                perror("fork");
                exit(2);
        }else if(_pid==0){//child
                close(_pipe_fd[0]);
                int count =10;
                while(count--){
                    char buf[1024]="hello world\n";
                    fflush(stdout);
                        if(count>5)
                        {
                                write(_pipe_fd[1],buf,strlen(buf));
                        }
                        sleep(2);
               
                }
                close(_pipe_fd[1]);

        }
        else{//father
                close(_pipe_fd[1]);
                char buf[1024];
                int j=0;
                while(j++ < 15){
                        memset(buf,'\0',sizeof(buf));
                        ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));
                        if(_size<0){
                                perror("read");
                                exit(3);
                        }else{
                                printf("%s",buf);
                        }
                }
                        int status=0;
                        if(waitpid(_pid, &status,0)== _pid){
                                printf("wait sucess,sigcode:%d\n",status & 0xFF);
                        }
               
        }
        return 0;
}
程序运行结果:
hello world
hello world
hello world
hello world
wait sucess,sigcode:0
(四)如果所有指向管道读端的文件描述符都关闭了,这时有进程向管道的写端write ,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        int _pipe_fd[2]={-1,-1};
        int _pipe=pipe(_pipe_fd);
        if(_pipe<0){
                perror("pipe");
                exit(1);
        }
        int _pid=fork();
        if(_pid<0){
                perror("fork");
                exit(2);
        }else if(_pid==0){//child
                close(_pipe_fd[0]);
                int count =10;
                while(count--){
                    char buf[1024]="hello world\n";
                    fflush(stdout);
                        if(count>5)
                        {
                                write(_pipe_fd[1],buf,strlen(buf));
                        }
                        sleep(2);
                }

        }
        else{//father
                close(_pipe_fd[1]);
                char buf[1024];
                int j=0;
                while(j++ < 3){
                        memset(buf,'\0',sizeof(buf));
                        ssize_t _size=read(_pipe_fd[0],buf,sizeof(buf));
                        if(_size<0){
                                perror("read");
                                exit(3);
                        }else{
                                printf("%s",buf);
                        }
                }

                  close(_pipe_fd[0]);
                sleep(10);
                        int status=0;
                        if(waitpid(_pid, &status,0)== _pid){
                                printf("wait sucess,sigcode:%d\n",status & 0xFF);
                        }
               
        }
        return 0;
}
程序运行结果:
hello world
hello world
hello world
wait sucess,sigcode:13
(五)如果有指向管道读端的文件描述符没关闭,而持有管道读端的进程也没有向管道读数据,这时有进程从管道写端写数据,那么管道被写满后,再次write会被阻塞,直到管道中有空位置了才写入并返回。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        int _pipe_fd[2]={-1,-1};
        int _pipe=pipe(_pipe_fd);
        if(_pipe<0){
                perror("pipe");
                exit(1);
        }
        int _pid=fork();
        if(_pid<0){
                perror("fork");
                exit(2);
        }else if(_pid==0){//child
                close(_pipe_fd[0]);
                int count =10;
                while(1){
                    char buf[1024]="hello world\n";
                    fflush(stdout);
                    write(_pipe_fd[1],buf,strlen(buf));
                    sleep(2);
                }
        }
        else{//father
                close(_pipe_fd[1]);
                char buf[1024]
                int status=0;
                if(waitpid(_pid, &status,0)== _pid){
                        printf("wait sucess,sigcode:%d\n",status & 0xFF);
                }
                 sleep(10);
               
        }
        return 0;
}
程序运行结果便是一直被阻塞。

由此可见管道的特点为:
1):主要用于父子进程间的通信,或者是有血缘关系的进程。
2):是单向通信的,且内部有保护机制。
3):其生命周期随进程。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-202403-1-1.html 上篇帖子: 详细介绍Ubuntu man手册帮助应用 下篇帖子: U盘制作ubuntu安装盘 Linux 管道 通信
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表