linux_c开发(5-2)进程间通讯_管道通讯

管道通信

什么是管道?

管道是单向的、先进先出的,他把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。

管道创建

管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通讯,后者可用于同一系统中的任意两个进程间的通讯。

无名管道由pipe()函数创建:

int pipe(int filedis[2]);

当一个管道建立时,他会创建两个文件描述符:

filedis[0]用于读管道,filedis[1]用于写管道。

管道关闭

关闭管道只需要将这两个文件描述符关闭即可,可以使用普通的close函数逐个关闭。

eg:

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

int main(void)
{
    int pipe_fd[2];
    if(pipe(pipe_fd)<0)
    {
        printf("pipe creat error\n");
        return -1;
    }
    else
        printf("pipe creat success\n!");
    close(pipe_fd[0]);
    close(pipe_fd[1]);
}

管道读写

管道用于不同进程见得通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。

注意事项

必须在系统调用fork()前调用pipe()否则子进程将不会继承文件描述符。

例: pipe_rw.c

#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    int pipe_fd[2];
    pid_ pid;
    char buf_r[100];
    char* p_wbuf;
    int r_num;
    memset(buf_r,0,sizeof(buf_r));
/*创建管道*/
    if(pipe(pipe_fd)<0)
    {
        printf("pipe creat error\n");
        return -1;
    }
/*创建子进程*/
    if((pid=fork())==0)
    {
        printf("\n");
        close(pipe_fd[1]);
        sleep(2);/*让子进程停下里让父进程往管道里写东西*/
        if ((r_num=read(pipe_fd[0],buf_r,100))>0)
            {
            printf("%d number read from the pipe is %s\n",r_num,buf_r)
            }
        close(pipe_fd[0]);
        exit(0);
    }
    else if(pid>0)
    {
        close(pipe_fd[0];
        if(write(pipe_fd[1],"hello",5)!=-1)
            printf("parent write hello!\n");
        if(write(pipe_fd[1],"pipe",5)!=-1)
            printf("parent write pipe!\n");
        close (pipe_fd[1]);
        sleep(3);
        waitpid(pid,NULL,0);//等待子进程结束
        exit(0);
    }
    return 0;
}

命名管道

命名管道和无名管道基本相同,不同点是:无名管道只能由父子进程使用,但有名管道不相关的进程也能交换数据。

创建

#include<sys/types.h>
#include<sys/stat.h>

int mkfifo(const char* pathname,mode_t mode)

**pathname:**FIFO文件名

mode:属性

一旦创建了一个FIFO,就可以用open打开它,一般的文件访问函数(close、read、write等)都可以用于FIFO。

操作

当打开FIFO时,非阻塞标志(O_NONBLOCK)将对以后的读写产生如下影响:

1、没有使用O_NONBLOCK: 访问要求将阻塞。

2、使用O_NONBLOCK: 访问无法满足时不阻塞,立刻返回出错。errno是ENXIO.

例子: 使用mkfifo创建有名管道并实现两个进程之间的通讯。

/*fifo_read.c*/
#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 "/tmp/myfifo"

/*
 * 程序入口
 * */
int main(int argc,char** argv)
{
    char buf_r[100];
    int  fd;
    int  nread;

    printf("Preparing for reading bytes...\n");
    memset(buf_r,0,sizeof(buf_r));

    /* 打开管道 */
    fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
    if(fd==-1)
    {
        perror("open");
        exit(1);
    }
    while(1)
    {
        memset(buf_r,0,sizeof(buf_r));

        if((nread=read(fd,buf_r,100))==-1)
        {
            if(errno==EAGAIN)
                printf("no data yet\n");
        }
        printf("read %s from FIFO\n",buf_r);
        sleep(1);
    }
    /*后面三句话是不会被运行到的,但不会影响程序运行的效果当程序在上面的死循环中执行时收到信号后会马上结束运行而没有执行后面的三句话。这些会在后面的信号处理中讲到,现在不理解没有关系,这个问题留给大家学习了信号处理之后来解决。*/
    close(fd); //关闭管道
    pause(); /*暂停,等待信号*/
    unlink(FIFO); //删除文件
}
/*fifo_write.c
#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_SERVER "/tmp/myfifo"

/*
 * 程序入口
 * */
int main(int argc,char** argv)
{
    int fd;
    char w_buf[100];
    int nwrite;

    /*创建有名管道*/
    if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL|O_RDWR)<0)&&(errno!=EEXIST))
    {
        printf("cannot create fifoserver\n");
    }

    /*打开管道*/
    fd=open(FIFO_SERVER,O_WRONLY |O_NONBLOCK,0);
    if(fd==-1)
    {
        perror("open");
        exit(1);
    }

    /*入参检测*/
    if(argc==1)
    {
        printf("Please send something\n");
        exit(-1);
    }
    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);
    }
    close(fd); //关闭管道
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-03 12:33:32

linux_c开发(5-2)进程间通讯_管道通讯的相关文章

linux_c 开发(6-1)多线程程序设计_线程基础

多线程 线程(thread)技术早在60年代就被提出来了,但真正应用多线程到操作系统中去,实在80年代中期,solaris是这方面的佼佼者.传统的UNIX也支持线程的概念,但是在一个进程中只允许有一个线程,这样多线程就意味着多进程.现在多线程技术已经被许多操作系统所支持,包括Windows/NT.Linux. 优点: 和进程相比,它是一种非常"节俭"的多任务操作方式.在linux系统下,启动一个新的进程必须分配给他独立的空间地址,建立众多的数据表来维护他的代码段.堆栈段和数据段,这是一

linux_c开发(5-3)进程间通讯_信号通讯

信号通讯 信号(signal)机制是UNIX系统中最为古老的进程间通信机制,有很多条件可以产生一个信号: 1. 当用户按某些按键时,产生信号. 2. 硬件异常产生信号:除数为零,无效的存储访问等等.这些信号通常有硬件检测得到,将其通知内核,然后内核产生适当的信号通知进程,例如: 内核对正在访问一个无效存储区的进程产生一个SIGSEGV信号. 3.进程用kill函数将信号发送给另一个进程. 4. 用户可以用kill命令将信号发送给其他进程. 信号类型 几种常见的信号 SIGHUP: 从终端发来的结

Python之路(第三十九篇)管道、进程间数据共享Manager

一.管道 概念 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信. 先画一幅图帮助大家理解下管道的基本原理 现有2个进程A和B,他们都在内存中开辟了空间,那么我们在内存中再开辟一个空间C,作用是连接这两个进程的.对于进程来说内存空间是可以共享的(任何一个进程都可以使用内存,内存当中的空间是用地址来标记的,我们通过查找某一个地址就能找到这个内存)A进程可以不断的向C空间输送东西,B进程可以不断的从C空间读取东西,这

linux_c 开发(5-5)进程间通讯_消息队列

进程间通讯_消息队列 定义: UNIX早起通信机制之一的信号能够传送的信息量有限,管道则只能传送无格式的字节流,这无疑会给应用程序开发带来不便.消息队列(也称报文队列)则克服了这些缺点. 发展: 消息队列就是一个消息的链表.可以把消息看做一个记录,**具有特定的格式.进程可以向中按照一定的规则添加新消息:另一些进程则可以从消息队列中读取消息. 分类: 目前主要有两种类型的消息队列:POSIX消息队列 以及系统V消息队列,系统V消息队列目前被大量使用. 持续性:系统V消息队列是随内核持续的,只有在

linux_c开发(5-4)进程间通讯_共享内存通讯

共享内存 共享内存 是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快方法,一个进程向共享内存写入了数据,共享这个内存的所有进程就可以立刻看到其中内容. 共享内存实现分为两个步骤 1.创建共享内存,使用shmget函数. 2.映射共享内存,将创建的这段共享内存映射到具体的进程空间去,使用shmat函数. int shmget(key_t key,int size,int shmflg) key标志共享内存的键值:O/IPC_PRIVATE.当key的取值为IPC/PRIVATE

linux_c开发(5-1)进程间通讯_进程间通讯概念

目的:为什么进程间需要通信? 1.数据传输 一个进程需要将他的数据发送给另外一个进程. 2.资源共享 多进程之间共享同样的资源. 3.通知事件 一个进程需要向另一个或一组进程发送消息,通知他们发生了某种事件. 4.进程控制 有些进程希望完全控制另一个进程的执行(eg:debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道他的状态改变. 发展: linux进程间通讯(IPC)由以下及部分发展而来: 1.UNIX间进程通讯 2.基于system v进程间通讯 3.POSIX进

进程间的通讯(IPC)方式

为什么要进行进程间的通讯(IPC (Inter-process communication)) 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).资源共享:多个进程之间共享同样的资源.为了作到这一点,需要内核提供锁和同步机制.进程控制:有些进程希望完全控制另一个进程的执行

Android Studio创建AIDL文件并实现进程间通讯

在Android系统中,跨进程通信是非常普遍的事情,它用到了Binder机制处理进程之间的交互.Binder机制会开放一些接口给java层,供android开发工程师调用进程之间通信.这些接口android封装到了AIDL文件里,当我们项目用到跨进程通信时可以创建.aidl文件,.aidl文件可以协助我们达到跨进程的通信.下面简单介绍用AndroidStudio创建AIDL文件的过程. a.新建AIDL文件 1.项目文件夹右键---> new --->选择AIDL 2.自定义一个接口名称 3.

Android(IPC)进程间通讯1:详解Binder由来?

完整原文:http://tryenough.com/android-ipc1 Android开发的进程间通讯,整个Android的应用都依赖于binder做底层通信机制.而Linux中提供的进程间通讯方式并没有binder机制,那么android中为什么要单独创造这种通讯方式呢?带着这个问题,继续往下读. Linux中进程相关概念 Linux将系统内存划分成了 用户空间 和 内核空间 两部分: 用户空间 : 普通应用程序则运行在用户空间上,它们不能使用某些特定的系统功能,不能直接访问硬件,不能直