一、无名管道
- 无名管道时半双工的,就是对于一个管道来讲,只能读或者写
- 无名管道只能在相关、有共同祖先的进程间使用
- 一个fork或者exec调用创建的子进程继承了父进程的文件描述符

1,打开和关闭管道
int pipe(int filedes[2]);
//在你从一个管道中读写,管道必须存在
//如果成功建立管道,则会打开两个文件描述符,并把它们的值保存在一个数值
//第一个文件描述符用于读数据,第二个文件描述符用于写数据
//出错返回-1,同时设置errno
//关闭一个管道用close()函数
//不能两端进行读写

/*读写无名管道例子*/
int main()
{
    int fd[2];//管道描述符
    char buf[100];//存放管道收发数据
    int len;//记录长度

    pipe(fd);
    memset(buf,0,sizeof(buf));//清空buf
    int pid = fork();
    if(pid == 0)
    {
        close(fd[1]);//关闭写管道
        while(len = read(fd[0],buf,sizeof(buf) >0)//len大于
            {
                write(STDOUT_FIFLNO,buf,len);
            }

        close(fd[0]);

    }
    else
    {
        close(fd[0]);//关闭读管道
        strcpy(buf,"hello world\n");
        write(fd[1],buf,sizeof(buf));
        close(fd[1]);
        waitpid(pid,NULL,0);

    }
    return 0;
}

二、有名管道(FIFO)
- 有名管道是持久稳定的
- 它们存在于文件系统中
- 可以让无关联的进程之间通信

1,用shell命令建立有名管道mkfifo [option] name
#mkfifo fifo1 //创建一个有名管道
#cat < fifo1  //通过cat向管道读取数据
#ls  > fifo1  //通过ls向管道输出数据

2,函数创建FIFO
int mkfifo(const char *pathname,mode_t mode)
//函数执行成功返回0,否则返回-1,并设置变量errno
int unlink(const char*pathname)
//删除fifo文件,执行成功返回0,否则返回-1,并设置变量errno

int main()
{
    mkfifo("fifo1",0666);
    //mode:rw-rw-rw为权限
    unlink("fifo1");
    return 0;

}

3,读写FIFO文件

//读FIFO例子
int main()
{
    int len = 0;
    char buf[100];
    memset(buf,0,sizeof(buf));
    int fd = open("fifo1",O_RDONLY);//只读方式
    while(len = read(fd[0],buf,sizeof(buf) >0)
    {
        printf("%s",buf);
        memset(buf,0,sizeof(buf));
    }
    close(fd);
    return 0;

}

//写FIFO例子
int main()
{

    char buf[100];
    memset(buf,0,sizeof(buf));
    int fd = open("fifo1",O_WRONLY);//只写方式
    while()
    {
        read(STDIN_FIFLNO,buf,sizeof(buf));
        if(buf[0] == '0')//如果输入字符0,退出循环
            break;
        write(fd,buf,strlen(buf));
        memset(buf,0,sizeof(buf));
    }
    close(fd);
    return 0;

}

4,共享内存
- 共享内存是内核处于在多个进程之间交换
  信息二留出的一块内存区
- 如果段的权限设置恰当,每个要访问该段
  内存的进程都可以把它映像到自己的私有空间
- 如果一个进程更新了段中的数据,其他进程也
  会立即看到更新
- 由一个进程创建的段,也可以由另一个进程读写
- 每个进程都把自己对共享进程内存的映像放到自
  己的内存空间

1)创建共享内存区

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,size_t size,int shm_flg);
//参数key既可以是IPC_PRIVATE,也可以是ftok函数返回的一个关键字
//参数size指定段的大小。
//参数flag:八进制数,0XXX。转化为二进制权限
//shmget成功返回段标示符,失败返回-1。
int shmctl(id, IPC_RMID, 0);
//删除共享内存的函数

/*创建共享内存区*/
int main()
{
    int shmid = shmget (IPC_PRIVATE,1024,0666);
    if(shmid < 0)
        printf ("error\n");
    else
        printf ("success\n");
    return 0;
    //在命令行执行ipcs -m 显示成功创建的共享内存信息
    //nattch:已经附加到这个内存的进程数
    //在命令行执行ipcrm shm shmid 删除共享内存
}

2)附加共享内存区
void *shmat (int shmid,const void *shmaddr,int shmfg );
//参数shmid是要附加的共享内存标示符
//总是把参数shmaddr设置为0
//参数shmflg可以为SHM_RDONLY,这意味着附加段是只读
//shmat成功返回被附加了段的地址,失败返回-1,并设置变量errno
int shmdt (const void *shmaddr );
//函数shmdt将附加在shmaddr的段从调用进程的地址空间分离出去,这个地址必须shmat返回

/*附加,释放共享内存区*/
int main(int argc,char *args[])
{
    char* shmbuf;
    int shmid = 0;
    if(arg > 1)
    {
        shmid = atoi(args[1]);//传入共享内存id
        shmbuf = shmat(shmid,0,0);
        sleep(60);
        shmdt(shmbuf);
    }
    return 0;

}

3)读写共享内存区
/*附加,释放共享内存区*/
int main(int argc,char *args[])
{
    char* shmbuf;
    int shmid = 0;
    if(arg > 2)
    {
        shmid = atoi(args[1]);//传入共享内存id
        shmbuf = shmat(shmid,0,0);
        if (atoi(args[2] == 1))//write shared mem
        {
            scanf ("%s\n",shmbuf);
        }
        if(atoi(args[2] == 2)//read shared mem
        {
            printf ("%s\n",shmbuf);
        }

        shmdt(shmbuf);
    }
    return 0;

}

备份地址: 【Linux进程间通信