进程间的通信简介

一、进程间的通信
    1、linux下进程间通信概述
        进程间通信就是在不同进程之间传播或交换信息。
        进程间通信(IPC interprocess communication)主要包括以下几种:
            1、管道及有名管道
                管道:具有亲缘关系进程间的通信
                有名管道:可以在许多不相关的进程之间进行通信
            2、信号(signal):用于通知接收进程有某种事件发生
            3、报文(message)队列(消息队列):消息队列是消息的链接表
            4、共享内存:使多个进程可以访问同一块内存空间
            5、信号量:作为进程间以及同一进程不同线程之间的同步手段
            6、套接字(socket):可用于不同机器之间的进程间通信。
        
    2、管道通信(连接一个进程的标准输入到另一个进程的标准输出的方法)
        
        1、管道
            当进程创建一个管道时,系统内核设置了两个管道可以使用的文件描述符。(write,read)
            
            特点:
                管道是半双工的
                只能用于具有亲缘关系的进程
                单独构成一种独立的文件系统
                数据的读出和写入:(FIFO)写入的内容每次都添加在管道缓冲区的末尾,
                                  并且每次都是从缓冲区的头部读出数据
            
            (1)管道的创建
            pipe()函数用于创建无名管道,当管道创建时会创建fd[0]和fd[1]两个文件描述符
            函数原型:
                int pipe(int fd[2])
                
                    fd[2]: fd[0]固定用于读管道,fd[1]固定用于写管道
                    返回值:成功——返回0; 失败——返回-1
            
            (2)管道的关闭
            close(): 关闭了fd[0]和fd[1]就关闭了管道
            
            (3)管道的读/写操作
                写操作:

                    close(fd[0]);//关闭读取端
                    sleep(3);//确保已关闭相应的读描述符
                    write(fd[1],string,strlen(string));//通过写端将字符串写入管道
                    close(fd[1]);//关闭写描述符

                读操作:

                    close(fd[1]);//关闭写入端
                    read(fd[0],readbuffer,sizeof(readbuffer));//从管道中读取字符串
                    printf("%s",readbuffer);
                    close(fd[0]);//关闭读描述符

                    
        2、标准流管道
            创建管道:FILE * popen(char * command, char * type)
                command: 启动shell后执行的命令
                type: 管道中数据流的方向w/r,不能同时为读和写(type只以第一个字符代表的方式打开)。
            关闭管道:int pclose(FIFE * stream);
            读写:fputs函数和fputc函数
            
        3、有名管道(FIFO管道)
            有名管道指创建的管道文件是有文件名的,任何程序都可以通过文件名或路径名与这个文件挂上钩
            FIFO管道不是一个临时对象,而是在文件系统中作为一个特殊的设备文件而存在的实体。
            
            (1)FIFO的创建
            FIFO文件即”先进先出“文件,
            创建方法:
                mknod MYFIFO p
                mkfifo a = rw MYFIFO
                
                以上的两个命令执行同样的操作,但其中有一点不同。mkfifo提供一个在创建之后改变FIFO文
                件存取权限的途径,而mknod需要调用命令chmod。
            mkfifo函数原型:
                int mkfifo(const char * pathname, mode_t mode)
                
                pathname: 将在文件系统中创建的一个专用文件
                mode:规定FIFO的读/写权限
                返回值:成功——返回0;失败——返回-1
                
            (2)使用
                有名管道可以用于任意两个进程间通信。由于管道都是单向的,因此双方通信需要两个管道。
                示例:
                写入数据:

                    mkfifo(namedpipe, 0777);//创建管道
                    pipe_fd = open(namedpipe, O_WRONLY);//以只写方式打开
                    sour_fd = open(sourtxt, O_RDONLY);//以只读方式打开源文件
                    bytes_read = read(sour_fd, buffer, sizeof(buffer));
                    buffer[bytes_read] = '\0';
                    while(bytes_read > 0) {//向管道写入数据
                        write(pipe_fd, buffer, sizeof(buffer));
                        bytes_read = read(sour_fd, buffer, sizeof(buffer));
                        buffer[bytes_read] = '\0';
                    }

                读取数据:

                    pipe_fd = open(namedpipe, O_RDONLY);//以只读方式打开管道
                    dest_fd = open(desttxt, O_WRONLY|O_CREAT, 0664);
                    bytes_read = read(pipe_fd, buffer, sizeof(buffer));
                    do {//从管道读出数据到目标文件
                        count = read(pipe_fd, buffer, sizeof(buffer));
                        write(dest_fd, buffer,sizeof(buffer));
                    } while (count > 0)

        
    三、共享内存通信
        共享内存:最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是 ——
        同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的
        更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制(互斥锁、信号量)
        
        对于系统V共享内存,主要有以下几个API:shmget(),shmat(),shmdt(),shmctl()
            shmget(): 获取共享内存区域的ID,不存在指定共享区域则创建相应的区域
            shmat():把共享内存区域映射到调用进程的地址空间中去
            shmdt():接触进程对共享内存区域的映射
            shmctl():实现对共享内存区域的控制操作
        函数原型:
            int shmget(key_t key, int size, int shmflg)
            
                key:IPC结构的键值,通常取常量IPC_PRIVATE
                size: 共享内存区的大小(新建时必须制定size大小,引用已有的区域,则size设为0)
                shmflg:权限位,可以用八进制表示
                返回值:成功——返回共享内存区域标识符ID,即shmid;出错——返回-1
            
            char * shmat(int shmid, const void * shmaddr, int shflg)
            
                shmid: 通过shmget得到的共享内存区标识符ID
                shmaddr:将共享内存映射到指定位置。0 —— 表示映射到调用进程的地址空间
                shmflg: 选项位,设置权限,常用选项是SHM_RDONLY(只读),默认为0(读写)。
                返回值:成功——返回被映射的段地址,失败——返回-1
                
                (使用以上两个函数即可以使用这段共享内存了,也就是可以使用不带缓冲的I/O读/写命令对
                    其进行操作)
                
            int shmdt(const void * shmaddr)
                
                shmaddr: 表示被映射的共享内存段地址
                返回值:成功——返回0;失败——返回-1