zoukankan      html  css  js  c++  java
  • Linux进程间通信(1):管道

    接上一篇的内容——Linux任务、进程和线程

    参考书籍:《从实践中学嵌入式linux应用程序开发》(华清远见嵌入式学院)

    资料下载:http://download.csdn.net/detail/klcf0220/5332477

    参考链接:http://www.cnblogs.com/zhouyinhui/archive/2010/10/13/1849203.html

    http://www.ibm.com/developerworks/cn/linux/l-ipc/part1/

    Linux进程间通信:

    1、同主机进程间数据交互机制:无名管道(PIPE)、有名管道(FIFO)、消息队列(Message Queue)和共享内存(Share Memory)。
    2、同主机进程间同步机制:信号量(semaphore)。
    3、同主机进程间异步机制:信号(Signal)。
    4、网络主机间数据交互机制:套接字(Socket)

    无名管道(pipe):

    首先是 int pipe(int f[2]) 这个函数,其需要头文件<unistd.h>,这个函数将创建一个未命名管道,并将管道的读端描述字包含在f[0]中,将写端描述字放在f[1]中,然后你就可以像利用普通文件描述字一样来读写数据了。
    再次是int close(int fd) 函数, 其需要头文件<unistd.h>,其用于关闭指定的文件描述字。
    最后是write和read函数, 其需要头文件<unistd.h>,用于读写数据。

    无名管道的特点:
        1、管道是半双工的,数据只能向一个方向流动,具有固定的读端和写端;需要双方通信时,需要建立起两个管道;
        2、只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
        3、单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是单独构成一种文件系统,并且只存在与内存中。
        4、数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

    管道读写注意点:

    1. 只有在管道的读端存在时,向管道写入数据才有意义。否则向管道写入数据的进程将收到内核传来的SIGPIPE信号(通常为Broken pipe错误);
    2. 向管道写入数据时,Linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读取管道缓冲区中的数据,那么写操作将会一直阻塞;
    3. 父子进程在运行时,它们的先后顺序并不能保证。
    /*pipe.c*/
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #define BUFF_SZ 256
    int main()
    {
        printf("app start...\n");
        pid_t          pid;
        int            pipe_fd[2];
        char           buf[BUFF_SZ];
        const char     data[] = "hi, this is the test data";
        int            bytes_read;
        int            bytes_write;
        //clear buffer, all bytes as 0
        memset(buf, 0, sizeof(buf));
        //creat pipe
        if(pipe(pipe_fd) < 0)//创建管道
        {
            printf("[ERROR] can not create pipe\n");
            exit(1);
        }
        //fork an new process
        if(0 == (pid=fork()))//创建一个子进程
        {
            //close the write-point of pipe in child process
            close(pipe_fd[1]);
            //read bytes from read-point of pipe in child process
            if((bytes_read = read(pipe_fd[0], buf, BUFF_SZ)) > 0)//子进程读取管道内容
            {
                printf("%d bytes read from pipe : '%s'\n", bytes_read, buf);
            }
            //close read-point of pipe in child process
            close(pipe_fd[0]);//关闭子进程读描述符
            exit(0);
        }
        //close read-point of pipe in parent process
        close(pipe_fd[0]);
        //write bytes to write-point of pipe in parent process
        if((bytes_write = write(pipe_fd[1], data, strlen(data))))
        {
            printf("%d bytes wrote to pipe : '%s'\n", bytes_write, data);
        }
        //close write-point of pipe in parent process
        close(pipe_fd[1]);
        //wait child process exit
        waitpid(pid, NULL, 0);//收集子进程退出信息
        printf("app end\n");
        return 0;
    }

    标准流管道:

    标准流管道完成的工作:

    1. 创建一个管道;
    2. fork()一个子进程;
    3. 在父子进程中关闭不需要的文件描述符;
    4. 执行exec()函数族调用;
    5. 执行函数中所调用的指令。

    使用实例:

    /*standard_pipe.c*/
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<fcntl.h>
    #define BUFSIZE 1024
    int main()
    {
        FILE *fd;
        char *cmd = "ps -ef";
        char buf[BUFSIZE];
        if((fd=popen(cmd,"r"))==NULL)//调用popen函数执行相应的命令
        {
            printf("popen fail\n");
            exit(1);
        }
        while((fgets(buf,BUFSIZE,fd)) != NULL)
        {
            printf("%s",buf);
        }
        pclose(fd);//关闭流管道
        exit(0);
    }

    有名管道(FIFO):

    1. 它可以使不相关的两个进程实现彼此通信;
    2. 该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作,使用非常方便;
    3. FIFO严格地遵循先进先出规则,对管道及FIFO的读总是从开始处返回数据,对它们的写则是把数据添加到末尾,它们不支持如 lseek() 等文件操作。

    函数 int mkfifo (char* path, mode_t mode) 负责创建FIFO管道,其需要头文件<sys/stat.h>,参数path即要创建的管道文件存放位置,mode参数即文件权限。
    更多的参考:http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html。     FIFO管道创建完成以后,便可以使用open函数来打开它,然后进行读写操作了。

    /*fifo_write.c*/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>

    #define BUFFER_SIZE PIPE_BUF
    #define FIFO_NAME "/tmp/my_fifo"

    int main()
    {
        int pipe_fd;
        //if the pipe file do not exist
        if (access(FIFO_NAME, F_OK) == -1)
        {
            //creat FIFO pipe file
            mkfifo(FIFO_NAME, 0777);
        }
        //open FIFO pipe file.
        pipe_fd = open(FIFO_NAME, O_WRONLY);
        //write data into pipe 
        write(pipe_fd, "hi, this is a test", PIPE_BUF);
        //close FIFO pipe file descriptor
        close(pipe_fd);
        return 0;
    }
    /*fifo_read.c*/
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #define FIFO_NAME "/tmp/my_fifo"
    #define BUFFER_SIZE PIPE_BUF
    int main()
    {
        int pipe_fd;
        char buffer[BUFFER_SIZE + 1];
        //reset all bytes in buffer as '\0' 
        memset(buffer, '\0', sizeof(buffer));
        //open FIFO pipe file.
        pipe_fd = open(FIFO_NAME, O_RDONLY);
        if(read(pipe_fd, buffer, BUFFER_SIZE) > 0)
        {
            printf("data from FIFO : %s\n", buffer);
        }
        //close pipe file descriptor
        close(pipe_fd);
        return 0;
    }
    作者:快乐出发0220 ;Android群:151319601 ; Linux群:96394158 ;转载请注明出处 http://klcf0220.cnblogs.com/ !!!
  • 相关阅读:
    react特点和创建虚拟DOM
    vue的keep-alive
    JavaScript-事件委托
    vue-router参数传递
    js常用的字符串处理
    vue-vuex
    vue-组件
    vue-父子组件传值
    堆和栈
    js-深拷贝浅拷贝
  • 原文地址:https://www.cnblogs.com/klcf0220/p/3060423.html
Copyright © 2011-2022 走看看