进程间通信——管道

一、进程间通信的目的

    1.数据传输:一个进程需要将它的数据发送给另一个进程。

    2.资源共享:多个进程之间共享同样的资源。

    3.通知事件:一个进程需要给另一个或是一组进程发送消息,通知它们发生了某种事件,(比如进程终止时要通知父进程)。

    4.进程控制:有些进程希望控制另一个进程,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。


二、什么是管道

    1.管道是Unix中最古老的进程间通信的形式。

    2.我们把从一个进程到另一个进程的一个数据流成为“管道”。


三、管道的分类

    1.匿名管道

    2.命名管道


 匿名管道是在函数中实现的,没有直接命令,而且要清楚文件描述符表中的0,1,2号下标对应的是stdin,stdout,stderror.

#include<unistd.h>
功能:创建一无名管道
原型:
int pipe(int fd[2]);
参数:fd:文件描述符数组,fd[0]:读端,fd[1]:写端。返回值:成功为0;失败返回错误码。

以下是一个从键盘中读入数据,然后写入管道,在读取管道,写到屏幕的代码实现。仅供参考:

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

int main()
{
    int fds[2];
    char buf[128];
    int len;
    if(pipe(fds) == -1)
    {
        perror("make pipe");//创建失败
        exit(1);
    }
    while(fgets(buf,128,stdin))
    {
        len = strlen(buf);
        //write into pipe
        if(write(fds[1],buf,len) != len)
        {
            perror("write to pipe");
            break;
        }
        memset(buf,0x00,sizeof(buf));
        //read from pipe
        if(len = read(fds[0],buf,128) == -1)
        {
            perror("read from pipe");
            break;
        }
        //write to stdout
        if(write(1,buf,len) != len)
        {
            perror("write to stdout");
            break;
        }
    }

    return 0;
}

其中有几个系统调用,

char *fgets(char *s, int size, FILE *stream);
  ssize_t write(int fildes, const void *buf, size_t nbyte);
   ssize_t read(int fildes, void *buf, size_t nbyte);


如果用fork来实现共享管道:




如果这个看不懂的话,没关系,再来有一个简单的,




来看一下代码的实现,

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


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


int main(int argc,char* argv[])
{
    int pipefd[2];
    if(pipe(pipefd) == -1)
    {
        ERR_EXIT("pipe error");
    }

    pid_t pid = fork();
    if(pid == -1)
    {
        ERR_EXIT("fork error");
    }
    if(pid == 0)
    {
        close(pipefd[0]);//关闭子进程的读端
        write(pipefd[1],"helloworld",10);
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }

    close(pipefd[1]);//关闭父进程的写端
    char buf[11] = {0};
    read(pipefd[0],buf,11);
    printf("buf = %s\n",buf);
    return 0;
}

命名管道:

    命令行输入 mkfifo filename

    也可以在程序中创建:

 int mkfifo(const char *pathname, mode_t mode);

    匿名管道和命名管道的区别只在于它们的创建与打开方式不同,匿名管道(pipe创建并打开),命名管道(open打开)。

下面用命名管道实现文件拷贝:

读取文件。写入命名管道。

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

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

int main()
{
    mkfifo("tp",0644);
    int infd = open("abc",O_RDONLY);
    if(infd == -1)
    {
        ERR_EXIT("open");
    }
    int outfd = open("tp",O_WRONLY);
    if(outfd == -1)
    {
        ERR_EXIT("open");
    }
    char buf[1024];
    int n;
    while((n = read(infd,buf,1024)) > 0)
    {
        write(outfd,buf,n);
    }
    close(infd);
    close(outfd);
    
    return 0;
}


读取管道,写入目标文件:

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

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

int main()
{
    int outfd = open("abc.bak",O_WRONLY|O_CREAT|O_TRUNC,0644);
    if(outfd == -1)
    {
        ERR_EXIT("open");
    }
    int infd = open("tp",O_RDONLY);
    if(infd == -1)
    {
        ERR_EXIT("open");
    }
    char buf[1024];
    int n;
    while((n = read(infd,buf,1024)) > 0)
    {
        write(outfd,buf,n);
    }
    close(infd);
    close(outfd);
    unlink("tp");
    
    return 0;
}

在看一个管道间的相互通信吧。

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


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



int main()
{
    umask(0);//设置权限
    if(mkfifo("mypipe",0644) < 0)
    {
        ERR_EXIT("mkfifo");
    }
    int rfd = open("mypipe",O_RDONLY);
    if(rfd < 0)
    {
        ERR_EXIT("open");
    }
    
    char buf[1024];
    while(1)
    {
        buf[0] = 0;
        printf("please wait...\n");
        ssize_t s = read(rfd,buf,sizeof(buf)-1);//没有回车字符
        if(s > 0)
        {
            buf[s-1] = 0;
            printf("client say:%s\n",buf);
        }
        else if(s == 0)
        {
            printf("client quit,exit now!\n");
            exit(EXIT_SUCCESS);
        }
        else
        {
            ERR_EXIT("read");    
        }
    }
    close(rfd);
    return 0;
}

client.c

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


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



int main()
{
    int wfd = open("mypipe",O_WRONLY);
    if(wfd < 0)
    {
        ERR_EXIT("open");
    }
    
    char buf[1024];
    while(1)
    {
        buf[0] = 0;
        printf("please Enter...\n");
        fflush(stdout);
        ssize_t s = read(0,buf,sizeof(buf)-1);//没有回车字符
        if(s > 0)
        {
            buf[s] = 0;
            write(wfd,buf,strlen(buf)); 
        }
        else
        {
            ERR_EXIT("read");    
        }
    }
    close(wfd);
    return 0;
}

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DuckyLoser/article/details/79946661
个人分类: Linux 学习笔记
上一篇顺序队列和链式队列 实现入队列, 出队列, 和取队首元素
下一篇进程间通信——消息队列
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭