精华内容
下载资源
问答
  • 名称:利用有名管道实现进程间通信(聊天小程序) 说明:此程序,是有名管道实现进程间的相互通信。 关于有名管道,需要说的是,它是一个特殊的文件,因为它的名字会保存在文件系统中(inode节点,这也是其为...

    /*
    名称:利用有名管道实现进程间通信(聊天小程序)
    说明:此程序,是利用有名管道实现进程间的相互通信。
    关于有名管道,需要说的是,它是一个特殊的文件,因为它的名字会保存在文件系统中(inode节点,这也是其为什么能在无关进程间通信的原因吧)但是,它的内容并不是在内存中(无名管道的名字和内容都是放在内存中的)。
    关于管道的建立,有一点要说明的就是一般来说,我们只需要把管道的打开方式设置成阻塞的(默认)的就可以,但是这个程序中,要把管道设置成非阻塞的(因为你也不知道对方什么时候会发给你,你什么时候会发送消息给对方)。在设置管道非阻塞的时候,需要用到一个新的函数,就是fcntl()(我把它叫做文件控制函数)。它可以把文件描述符所代表的文件流(此处是管道流)设置成非阻塞的。
    其次,由于要双向通信,而命名管道一般用于单双工通信,所以需要两个管道。但是比较气人的是,由于种种原因(我也不清楚的原因)在设置打开非阻塞管道是时候,必须先打开读端,再打开写端,再打开写端,否则就会出错。由于这个原因,我们不能同时打开两个文件管道(因为在一个进程中需要以读方式打开一个管道,在以写方式打开一个管道),如果同时打开的话,会出错。为了解决这个问题,我让server首先打开pipe1的读端,然后一直监听是否有消息,如果有消息的话在打开另一个管道写端。这样的话,在运行程序的时候只能先让server程序先运行了。

    */

    //server端
    #include <unistd.h>  
    #include <stdlib.h>  
    #include <stdio.h>  
    #include <fcntl.h>  
    #include <sys/types.h>  
    #include <sys/stat.h>  
    #include <limits.h>  
    #include <string.h>
    
    #include <fcntl.h> 
    
    
    
    //初始化函数,用于非阻塞标准输入
    int Init()
    {
        if(-1 == fcntl(0,F_SETFL,O_NONBLOCK))
        {
            printf("fail to change the  std mode.\n");
            return -1;
        }
    
    
    }
    
    int main()
    {
        int pipe_fd1,pipe_fd2;
        int read_cou = 0,write_cou = 0;
        char read_buf[100];
        char write_buf[100];
        memset(read_buf,'\0',sizeof(read_buf));
        memset(write_buf,'\0',sizeof(write_buf));
    
        //判断管道是否存在,如果不存在就创建有名管道
        if(-1 == access("pipe1",F_OK))
        {
            if(-1 == mkfifo("pipe1",0777))
            {
                printf("Could not create pipe1\n");
                return -1;
            }
        }
    
        if(-1 == access("pipe2",F_OK))
        {
            if(-1 == mkfifo("pipe2",0777))
            {
                printf("Could not create pipe2\n");
                return -1;
            }
        }
    
        //先打开一个管道,此管道用于server读,client写。非阻塞打开
        pipe_fd1 = open("pipe1",O_RDONLY | O_NONBLOCK);
    
        Init();
    
    
        //这个while循环用于检测是否有client提出访问请求(发来信息)
        while(1)
        {
            read_cou = read(pipe_fd1,read_buf,PIPE_BUF); //从管道中读取数据
            if(read_cou > 0)        
            {
                printf("receive client:%s\n",read_buf);
                pipe_fd2 = open("pipe2",O_WRONLY | O_NONBLOCK); //如果首次提出请求,则打开第二个管道用于server写,client读
                break;
            }
    
    
        }
    
    
        //正式交流信息阶段
        while(1)
        {
            //读出过程
            read_cou = read(pipe_fd1,read_buf,PIPE_BUF);
            if(read_cou > 0)
            {
                printf("server receive :%s\n",read_buf);
            }
    
            //从标准输入中读取,如果有输入再写入管道
            if (gets(write_buf) != NULL)
            {
                printf("server input:%s.\n",write_buf);
                write(pipe_fd2,write_buf,sizeof(write_buf));
            }
    
        }
        return 0;
    }
    //client端:
    #include <unistd.h>  
    #include <stdlib.h>  
    #include <stdio.h>  
    #include <fcntl.h>  
    #include <sys/types.h>  
    #include <sys/stat.h>  
    #include <limits.h>  
    #include <string.h>  
    
    #include <fcntl.h> 
    
    //初始化函数,用于非阻塞标准输入
    int Init()
    {
        if(-1 == fcntl(0,F_SETFL,O_NONBLOCK))
        {
            printf("fail to change the  std mode.\n");
            return -1;
        }
    
    
    }
    
    int main()
    {
        int pipe_fd1,pipe_fd2;
        int read_cou = 0,write_cou = 0;
        char read_buf[100];
        char write_buf[100];
        memset(read_buf,'\0',sizeof(read_buf));
        memset(write_buf,'\0',sizeof(write_buf));
    
        //判断管道是否存在,如果不存在就创建有名管道
        if(-1 == access("pipe1",F_OK))
        {
            if(-1 == mkfifo("pipe1",0777))
            {
                printf("Could not create pipe1\n");
                return -1;
            }
        }
    
        if(-1 == access("pipe2",F_OK))
        {
            if(-1 == mkfifo("pipe2",0777))
            {
                printf("Could not create pipe2\n");
                return -1;
            }
        }
    
        //打开两个管道,其中pipe1用于server读,pipe2用于server写(非阻塞打开)
        pipe_fd1 = open("pipe1",O_WRONLY | O_NONBLOCK);
        pipe_fd2 = open("pipe2",O_RDONLY | O_NONBLOCK);
    
        Init();
    
        //此循环用于首先向server提出请求,是server打开第二个通信管道
        while(1)
        {
            //写入过程
            if (gets(write_buf) != NULL)
            {
                printf("client input:%s.\n",write_buf);
                write(pipe_fd1,write_buf,sizeof(write_buf));
                sleep(1);
                break;
            }
        }
    
    
        //和server正式通信
        while(1)
        {
            //读出过程
            read_cou = read(pipe_fd2,read_buf,PIPE_BUF);
            if(read_cou > 0)
            {
                printf("client receive :%s\n",read_buf);
            }
    
            //写入过程
            if (gets(write_buf) != NULL)
            {
                //从标准输入中读取,如果有输入再写入管道
                printf("client input:%s.\n",write_buf);
                write(pipe_fd1,write_buf,sizeof(write_buf));
            }   
    
        }
    
        return 0;
    }
    展开全文
  • 无名管道类似于无名管道,一般都会和无名管道比较着来说 无名管道的创建 特点 用于同一台PC机的两个进程,...如果之前fifo管道内没有数据,读进程就会一直阻塞,一直阻塞到有数据写入或FIFO管道写端关闭 写操作...

    无名管道类似于无名管道,一般都会和无名管道比较着来说

    无名管道的创建

    在这里插入图片描述

    特点

    • 用于同一台PC机的两个进程,可以是亲缘进程,也可以是不相关的进程
    • 通过文件IO操作管道
    • 不支持lseek等跳转光标函数
    • 遵循先进先出的原则
    • 存在于文件系统中,可以看到。文件类型为p(管道文件)

    读写操作

    读操作

    • 如果之前fifo管道内没有数据,读进程就会一直阻塞,一直阻塞到有数据写入或FIFO管道写端关闭

    写操作

    • 只要FIFO中有空间,数据就可以写入,若空间不足,写进程就会阻塞,直到数据全部写入

    读端代码

    /*************************************************************************
    	> File Name: fifo_one.c
    	> 功能:创建一个管道,此程序用来读出管道中的数据 
    	> Mail: 
    	> Created Time: Thu 15 Aug 2019 12:45:50 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<string.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<fcntl.h>
    
    int main()
    {
        int fifo=0;
        int fd=0;
        int ret=0;
        char buf[1024]={0};
    //创建一个管道
       fifo= mkfifo("/home/linux/Desktop/myfifo",0666);
        if(fifo<0)
        {
            perror("mkfifo error");
            exit(-1);
        }
    //以只读模式,打开一个管道
        fd=open("/home/linux/Desktop/myfifo",O_RDONLY);
        if(fd<0)
        {
            perror("open error");
            exit(-2);
        }
        while(1)
        {
            ret=read(fd,buf,sizeof(buf));
            if(ret<0)
            {
                perror("read error");
                exit(-3);
            }
            if(ret==0)
            {
                printf("这次什么也没有读到\n");
                exit(66);
            }
            printf("这次读到的东西是%s\n",buf);
            memset(buf,0,sizeof(buf));
        }
        close(fd);
        remove("/home/linux/Desktop/myfifo");
    return 0;
    }
    

    写端代码

    /*************************************************************************
    	> File Name: fifo_two.c
    	> Author: 
    	> Mail: 
    	> Created Time: Thu 15 Aug 2019 01:34:46 AM PDT
     ************************************************************************/
    
    #include<stdio.h>
    #include<sys/types.h>
    #include<string.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<fcntl.h>
    
    int main()
    {
        int fd=0;
        int ret=0;
        char buf[1024]={0};
    
    //以只写模式打开一个管道文件
        fd=open("/home/linux/Desktop/myfifo",O_WRONLY);
        if(fd<0)
        {
            perror("open error");
            exit(-1);
        }
        while(1)
        {
            gets(buf);
            write(fd,buf,sizeof(buf));
            memset(buf,0,sizeof(buf));
        }
    return 0;
    }
    

    运行演示

    在这里插入图片描述

    展开全文
  • 有名管道实现进程间通信

    千次阅读 2017-12-25 16:07:09
    有名管道的出现就是为了解决这个限制问题,有名管道可以使互不相关的两个进程实现彼此通信通信的过程就是通过路径名来指出管道文件,然后在建立了管道联系之后两个进程就可以把它当做一个普通文件一样进行读写操作...

    有名管道介绍。

    使用pipe创建的无名管道只能用于具有亲缘关系的进程之间,这就大大限制了管道的使用。

    有名管道的出现就是为了解决这个限制问题,有名管道可以使互不相关的两个进程实现彼此通信。通信的过程就是通过路径名来指出管道文件,然后在建立了管道联系之后两个进程就可以把它当做一个普通文件一样进行读写操作,但是有名管道是严格遵循FIFO的规则,也就是所谓的先进先出,如果从有名管道中读取数据的话总是从开始出返回数据,显然如果是增加数据的话就是添加到末尾,而且不支持一些定位操作如lseek等。

    在我们使用有名管道的时候可以把管道当成一个文件,但是与普通文件不同的是有名管道需要考虑阻塞问题。在有关管道的使用中阻塞与不阻塞的主要区别如下:

    对于读进程:

    • 若该管道是阻塞打开,且当前FIFO内没有数据,则对度进程而言将一直阻塞直到有数据写入。
    • 若该管道是非阻塞打开,则不管当前FIFO中有没有数据,读进程都回立即执行操作并返回。

    对于写进程:

    • 若该管道是阻塞打开,则写进程而言将一直阻塞直到有读进程读出数据。
    • 若该管道是非阻塞打开,则不管当前FIFO中有没有读操作,都会执行写操作并返回。

    简单的说就是,打开一个管道之后,如果是非阻塞模式,则不论管道的两边(一边读一边写)有没有正在操作,都会直接返回。但是如果是阻塞模式,则必须要保证管道两边都要有进程同时操作,否则就会阻塞。


    创建有名管道。

    1. 可以通过”mknod 管道名 p”来直接创建一个有名管道,然后就可以直接使用read、write等操作。

    2. 也可以使用mkfifo函数来创建或者打开一个管道。

      mkfifo函数介绍:

      • 所需头文件:#include < sys/types.h> 、#include < sys/stat.h>
      • 函数原型:int mkfifo(const char* filename,mode_t mode)
      • 参数介绍:第一个就是管道名的名称,第二个参数是打开的模式,共有以下几种:
        1. O_RDONLY:读管道。
        2. O_WRONLY:写管道。
        3. O_RDWR:读写管道。
        4. O_NONBLOCK:非阻塞管道。
        5. O_CREAT:如果该文件不存在,就创建一个新的文件。
        6. O_EXCL:如果用O_CREAT时文件存在,那么可能会返回错误信息,如果使用这个参数则可以检测文件是否存在。
      • 返回值:成功:0;错误:-1.

    使用FIFO可能返回的错误信息:

    • EACCESS:参数filename所指定的目录路径无可执行的权限。
    • EEXIST:参数filename所指定的文件已存在。
    • ENAMETOOLONG:参数filename的路径名称太长。
    • ENOENT:参数filename包含的目录不存在。
    • ENOSPC:文件系统的剩余空间不足。
    • ENOTDIR:参数filename路径中的目录存在但却非真正的目录。
    • EROFS:参数filename指定的文件存在与只读文件系统内。

    使用实例。

    读操作:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define FIFO "/usr/leafage/testfifo"//定义一个管道名称
    
    int main(int argc,char** argv) {
        int fd;//管道描述符
        char buf_r[100];//用来读取管道信息
        int nread;//文件描述符
    
        //创建管道
        if((mkfifo(FIFO,O_CREAT|O_EXCL) < 0) && (errno!=EEXIST))
            printf("cannot create fifoserver\n");
        printf("Preparing for reading bytes...\n");
        //将数组中用0填充。
        memset(buf_r,0,sizeof(buf_r));
        //打开管道
        fd = open(FIFO,O_RDONLY|O_NONBLOCK,0);
        if(fd == -1) {
            perror("open failed");
            exit(1);
        }
        //循环读取
        while(1) {
            //清空buf_r数组
            memset(buf_r,0,sizeof(buf_r));
            //如果读取的长度为0的话说明此时还没有数据,否则从管道中读取出数据并输出。
            if((nread=read(fd,buf_r,100)) == 0) {
                printf("no data yet\n");
            } else {
                printf("read %s from FIFO\n",buf_r);
            }
            sleep(1);
        }
    }       
    

    写操作:

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define FIFO "/usr/leafage/testfifo"//定义管道名称
    
    int main(int argc, char** argv) {
        int fd;
        char w_buf[100];
        int nwrite;
    
        //创建管道
        if((mkfifo(FIFO,O_CREAT|O_EXCL) < 0) && (errno!=EEXIST))
            printf("cannot create fifoserver\n");
    
        //写模式打开管道,非阻塞
        fd = open(FIFO,O_WRONLY|O_NONBLOCK,0);
    
        if(fd==-1)
            if(errno==ENXIO)
                printf("open error; no reading process\n");
    
        //参数中作为写入管道的内容
        if(argc==1)
            printf("Please send something\n");
        strcpy(w_buf,argv[1]);
    
        //写入到管道中
        if((nwrite=write(fd,w_buf,100))==-1) {
            if(errno==EAGAIN)
                printf("The FIFO has not been read yet.Please try later\n");
        }else {
            printf("write %s to the FIFO\n",w_buf);
        }
    }
    
    • 非阻塞模式。
      上述是一个简单的读写操作,采用的是非阻塞模式。

    这里来测试一下看看有什么问题,如果先运行读操作,再运行写操作输出内容如下:

    这里写图片描述

    可以看到先启动读操作,此时管道中没有任何数据,所以一直循环下去,直到执行写操作像管道中写入数据,读操作才读取到数据。这个时候是没有问题的,但是如果先执行写操作就会出现问题,会出现如下错误提示:

    这里写图片描述

    通过代码可以看到该错误对应的就是出现了ENXIO异常,对ENXIO有这样的描述:

    ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process has the file open for reading. Or, the file is a device special file and no corresponding device exists.

    两种情况,显然属于第一种,打开的是一个FIFO,但是此刻并没有进程在读取,所以出现了该操作,这也是非阻塞模式下可能会出现的问题。

    • 阻塞模式。

    如果我们在打开管道的时候去掉“O_NONBLOCK”参数,就是阻塞模式了。

    同样的测试的时候先运行读操作,输出内容如下:

    这里写图片描述

    由于是非阻塞模式,所以先执行读操作的时候会发现管道的另一端并没有写操作进程,所以会一直阻塞起来,也就是执行了open函数时阻塞了,并没有进入while循环。直到写操作执行,然后才会执行下面while循环。

    如果是先执行写操作,再执行读操作,输出结果如下:

    这里写图片描述

    这次我们先执行写操作是并没有出现非阻塞模式中的ENXIO异常,这是因为发现了管道的另一端没有读操作,所以一直阻塞并不返回。然后读操作执行,写操作执行完成才返回。

    展开全文
  • 为什么说极简呢,因为下面这个程序只能从一端写另一端读。...注意:有名管道用于系统中任意两个进程间通信(不需要有亲缘关系)fifo_read.c#include #include #include #include #include #include #inclu

    为什么说极简呢,因为下面这个程序只能从一端写另一端读。(单工通信)
    注意:有名管道用于系统中任意两个进程间通信(不需要有亲缘关系)

    fifo_read.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    
    int main()
    {
        int ret, fd;
        char buf[100] = {0};
    
        ret = mkfifo("fifo.tmp", O_CREAT | O_EXCL);     //创建有名管道
        if (-1 == ret)      //创建失败
        {
            perror("fifo");
            exit(1);
        }
    
        fd = open("fifo.tmp", O_RDONLY);        //以只读方式打开
        if(-1 == fd)        //打开失败
        {
            perror("read");
            exit(1);
        }
    
        while(1)
        {
            ret = read(fd, buf, sizeof(buf));       //读出缓冲区中的内容
            if(ret == -1)
            {
                perror("read");
                exit(1);
            }
            if(!strncmp(buf, "bye", 3))     //以bye结束
            {
                break;      //跳出循环
            }
    
            printf("read from fifo.tmp: %s\n",buf);
            memset(buf, 0, sizeof(buf));    //清空缓冲区
            unlink("fifo.tmp"); //关掉管道文件,方便程序下次运行
        }
        return 0;
    }

    fifo_write.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main()
    {
        char buf[100] = {0};
        int fd, ret;
    
        fd = open("fifo.tmp", O_WRONLY);        //以只写方式打开
        if(-1 == fd)
        {
            perror("open");
            exit(1);
        }
    
        while(1)
        {
            scanf("%s",buf);
            ret = write(fd, buf, strlen(buf));      //往缓冲区里面写
            if(-1 == ret)
            {
                perror("write");
                exit(1);
            }
    
            if(!strncmp(buf, "bye", 3))     //以bye结束
            {
                break;
            }
        memset(buf, 0, sizeof(buf));        //清空缓冲区
        }
        return 0;
    }

    上面两个程序(进程)前者为读,后者为写,注意第一个程序里面首先要创建一个有名管道,所以两个程序运行的先后顺序是前者先运行(此时,一直读到空)。运行结果如下:

    这里写图片描述

    展开全文
  • 本实例为了展示,使用有名管道的方法,实现进行的消息传递。 实现须知: 1. 两个对象,服务器和客户端; 2. 有名管道需要创建的文件路径及文件名; 3. 有名管道的创建方法及消息发送机制; 具体事例如下: ...
  • 创建两个有名管道,分别用来读和写,用四个进程来完成。 //a用来读取信息,b用来写入信息的管道 #include "stdio.h" #include "stdlib.h" int main() { int ret; ret = mkfifo("./arfifo",0777); if(-1 == ret) ...
  • 利用有名管道实现进程间通信

    千次阅读 2018-02-27 21:20:11
    1 /***************************************************************** 2 * Copyright (C) 2018 FBI WARNING. All rights reserved. 3 * 4 * 文件名称:fifo_write.c 5 * 创 建 者:constantine 6 * ...
  • 常见的进程间通信方式 传统进程间通信方式 无名管道(pipe) 有名管道(fifo) 信号(signal) System V IPC 对象 共享内存(share memory) 消息队列(message queue) 信号灯(semaphore) System V IPC 对象 ...
  • Unix下管道实现进程间通信

    千次阅读 2016-12-05 12:39:41
    管道包括无名管道和有名管道两种,前者只能用于父进程和子进程间通信,后者可用于运行于同一系统中的任意两个进程间通信。下面用一个示意图来表示: 3. 管道通信的特点 管道通讯是单向的,先进先出,有固定的读...
  • 1.主要实现了,lucy进程和pete进程间通信交流。 代码就在这里,我自己在测试时遇到过bug,大家一块交流改进。 //pete #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #...
  • UNIX环境高级编程学习之第十五章进程间通信 - 通过有名管道(命名管道)实现进程间通信
  • 环境:linux C功能:有名管道fifo实现任意进程间通信/*create_fifo.c*/#include &lt;stdio.h&gt;#include &lt;stdlib.h&gt;#include &lt;unistd.h&gt;#include &lt;fcntl.h&gt;#...
  • 创建两个有名管道实现不同进程间的全双工通信。 两个进程聊天程序:一个server端,一个client端。 例子用到了read函数: read函数只是一个通用的读文件设备的接口。是否阻塞需要由设备的属性和设定所决定。...
  • 有名管道是通过在磁盘上创建一个管道类型的文件, 不同的进程可以通过读写这个文件实现通信。 和无名管道一样, 有名管道也是半双工通信类型, 同一时刻, 一端只能读, 另一端只能写。 与无名管道不同, 有名管道...
  • 进程间通信(二)有名管道

    千次阅读 2017-09-15 12:23:04
    有名管道FIFO依赖于文件系统,使得同主机任意进程间实现通信有名管道和普通文件一样具有磁盘存放路径、文件权限和其他属性。 但是有名管道并没有在磁盘中存放真正的信息,他存储的通信信息在内存中,两个进程...
  • 所以,有名管道可用于任意两进程之间的通信。 就有名管道和无名管道的实现来说,主要是在打开方式上有所不同,管道文件一旦打开(建立),以后两者对管道文件的读、写和关闭操作相同。int open (const char *path, ...
  • 有名管道解决了无名管道只能在亲缘进程间通信的弊端 相较于无名管道只能用于亲缘关系进程之间的通信,有名管道可以再任意两个进程间实现通信,该管道可以通过路径名使用,并且在文件系统中是可见的(无名管道不可见...
  • 无名管道是临时的,在完成通信后自动消息,因为文件描述符只能在某个进程中可见,因此被广泛用于具有亲缘关系的进程间通信,采用的方法是先创建管道,再创建进程,使子进程继承父进程创建的管道文件描述符。...
  • 利用有名管道文件实现进程间通信,要求1.写进程向有名管道文件写入10次“hello world”;2.读进程读取有名管道文件中的内容,并依次打印。源代码:w.c#include &lt;fcntl.h&gt;#include &lt;sys/types.h...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 375
精华内容 150
关键字:

有名管道实现进程间通信