• 嵌入式Linux C进程间通信(二)——管道


    一、无名管道的使用

    具体来说就是,内核会开辟-一个“管道”,通信的进程通过共享这个管道,从而实现通信。
    只能是父子进程之间进行通信(要有血缘关系)
    其他进程之间不行
    在这里插入图片描述
    int pipe(int pipefd[2])
    管道只允许单向通信
    读管道时,如果没有数据的话,读操作会休眠(阻塞入,写数据时,缓冲区写满会休眠(阻塞)
    数据被读出,数据就会被管道删除;

    #include 
    #include 
    #include 
    #include 
    
    int main(int argc, char const *argv[])
    {
        int fd[2];
        pid_t pid;
        int p = pipe(fd);
        if (p < 0)
        {
            perror("pipe error\n");
            exit(1);
        }
    
        pid = fork();
    
        if (pid < 0)
        {
            perror("fork error!\n");
            exit(1);
        }
    
        if (pid == 0)
        {
            
            char buffer[1024];
            close(fd[0]);
            
            while (1)
            {
                memset(buffer, 0, sizeof(buffer));
                scanf("%s", buffer);
                write(fd[1], buffer, strlen(buffer));
            }
        }
        else if (pid > 0)
        {
            char buffer[1024];
            close(fd[1]);
            /*改成非阻塞
            #include 
    		int flags = fcntl(fd[0],F_GETFL);
    		flags = flags | O_NONBLOCK;
    		fcntl(fd[0],F_SETFL,flags);
        	*/    
            while (1)
            {
                memset(buffer, 0, sizeof(buffer));
                sleep(1);
                read(fd[0], buffer, sizeof(buffer));
                printf("buffer = %s\n", buffer);
            }
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    二、SIGPIPE信号

    在这里插入图片描述

    SIGPIPE:写入没有读权限的管道文件---------终止

    #include 
    #include 
    #include 
    #include 
    #include 
    
    void my_exit(int b)
    {
        printf("SIGPIPE\n");
    }
    
    int main(int argc, char const *argv[])
    {
        int fd[2];
        pid_t pid;
        int p = pipe(fd);
        if (p < 0)
        {
            perror("pipe error\n");
            exit(1);
        }
    
        pid = fork();
        signal(SIGPIPE,my_exit);
        if (pid < 0)
        {
            perror("fork error!\n");
            exit(1);
        }
    
        if (pid == 0)
        {
            
            char buffer[1024];
            close(fd[0]);
            
            while (1)
            {
                memset(buffer, 0, sizeof(buffer));
                scanf("%s", buffer);
                write(fd[1], buffer, strlen(buffer));
            }
        }
        else if (pid > 0)
        {
            char buffer[1024];
            close(fd[1]);
            close(fd[0]);
            while (1)
            {
                memset(buffer, 0, sizeof(buffer));
                sleep(1);
                read(fd[0], buffer, sizeof(buffer));
                printf("buffer = %s\n", buffer);
            }
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    子进程会终止
    可以用signal(SIGPIPE,SIG_ING);将信号忽略

    三、有名管道

    系统中任意两个进程,都能进行通信

    为什么叫有名管道
    管道应用的一个重大限制是它没有名字,只适合具有亲缘性质的进程之间通信。命名管道克服了这种限制,FIFO不同于管道之处在于它提供-一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。

    int mkfifo(const char * pathname, mode_ t mode);

    在这里插入图片描述
    有名管道的使用步骤

    1. 进程调用mkfifo创建有名管道
    2. open打开有名管道
    3. read/write读写管道进行通信

    “有名管道”这种特殊文件,只能使用mkfifo函数来创建
    为了保证管道一定被创建,最好是两个进程都包含创建管道的代码,谁先运行就谁先创建,后运行的发现管道已经创建好了,那就直接open打开使用。
    不能以0_ RDWR模式打开命名管道FIFO文件,否则其行为是未定义的,管道是单向的,不能同时读写;

    3.1 父子进程通信

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define FILE_NAME "./file"
    
    int main(int argc, char const *argv[])
    {
        pid_t pid;
    
        if (mkfifo(FILE_NAME,0655) < 0)
        {
            perror("mkfifo error!");
            exit(1);
        }
    
        pid = fork();
    
        if (pid < 0)
        {
            perror("fork error!\n");
            exit(1);
        }
    
        if (pid == 0)
        {
            int fd = open(FILE_NAME, O_WRONLY);
            char buffer[1024];
            while (1)
            {
                memset(buffer, 0, sizeof(buffer));
                scanf("%s",buffer);
                write(fd,buffer,strlen(buffer));
            }
        }
        else if (pid > 0)
        {
            int fd = open(FILE_NAME, O_RDONLY);
            char buffer[1024];
            while (1)
            {
                memset(buffer, 0, sizeof(buffer));
                read(fd,buffer,sizeof(buffer));
    
                printf("buffer = %s\n",buffer);
            }
        }
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    3.2 独立进程之间通信

    3.2.1 read_mkfifo

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define FILE_NAME "./file"
    
    void my_exit(int sig)
    {
        remove(FILE_NAME);
    }
    
    int main(int argc, char const *argv[])
    {
        signal(SIGINT, my_exit);
        if (mkfifo(FILE_NAME, 0655) < 0)
        {
            perror("mkfifo error!");
            exit(1);
        }
        
        int fd = open(FILE_NAME, O_RDONLY);
        char buffer[1024];
        while (1)
        {
            memset(buffer, 0, sizeof(buffer));
            read(fd,buffer,sizeof(buffer));
    
            printf("buffer = %s\n",buffer);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3.2.2 write_mkfifo

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define FILE_NAME "./file"
    
    // void my_exit(int sig)
    // {
    //     remove(FILE_NAME);
    // }
    
    int main(int argc, char const *argv[])
    {
        //signal(SIGINT, my_exit);
        int fd = open(FILE_NAME, O_WRONLY);
        char buffer[1024];
        while (1)
        {
            memset(buffer, 0, sizeof(buffer));
            scanf("%s",buffer);
            write(fd,buffer,strlen(buffer));
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.2.3 运行结果

    在这里插入图片描述

  • 相关阅读:
    利用DownThemAll工具批量下载网页单一链接的数据
    Python:实现linear regression线性回归算法(附完整源码)
    征途服务端安装
    华纳云:如何实现数据库的读写分离?
    linux安装Jdk
    Java 小数过多出现E情况
    ubuntu20.04卸载cuda11.4重装cuda11.0
    JVM基础知识(内存区域划分,类加载,GC垃圾回收)
    8月初整理,Adobe 2022全家桶更新情况(Mac+win)限时分享
    【力扣】整数反转,判断是否溢出的数学解法
  • 原文地址:https://blog.csdn.net/m0_52592798/article/details/126191040