管道、FIFO(有名管道)、消息队列、信号量、信号、共享内存、套接字
1)管道/无名管道
Int pipe(int fd[2]);
返回值:成功返回0,失败返回-1,由fd[]返回两个文件描述符:fd[0]为读端、fd[1]为写端,fd[1]的输出是fd[0]的输入
管道是一种半双工通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,若需要双向的可以在两个进程间建立两个方向相反的管道
管道只能在有公共祖先的两个进程间使用,通常,一个进程先调用pipe()创建管道,然后再调用fork(),之后,父子进程会共享管道(文件描述符fd[0/1])
2)FIFO
Int mkfifo(const char* path, mode_t mode);
Int mkfifoat(int fd, const char* path, mode_t mode);
二者均返回:成功返回0,失败返回-1
命名管道,半双工管道,因为有命名,所以允许无亲缘关系的进程间通信,同理,可以建立两个FIFO来实现双向通信
无名管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小)
管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等
FIFO往往都是多个写进程,一个读进程。
http://blog.csdn.net/firefoxbug/article/details/8137762
3)信号
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
4)消息队列
消息队列是消息的链表,存放在内核中并由消息队列标识符(队列ID)标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
int msgget(key_t key, int flag); //打开一个现有队列或创建一个新队列,成功返回消息队列ID,失败返回-1
int msgctl(int msqid, int cmd, struct msqid_ds *buf); //对消息队列执行各种操作,如读取队列中信息,成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr,size_t nbytes, int flag); //将新消息添加到队列尾端,成功返回0,失败返回-1
int msgsnd(int msqid, const void *ptr,size_t nbytes, long type,int flag); //从队列中取消息,成功返回消息数据部分的长度,失败返回-1
5)共享内存
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
#include <sys/shm.h>
// 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
int shmget(key_t key, size_t size, int flag);
// 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
void *shmat(int shm_id, const void *addr, int flag);
// 断开与共享内存的连接:成功返回0,失败返回-1
int shmdt(void *addr);
// 控制共享内存的相关信息:成功返回0,失败返回-1
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。
当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。
shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。
6)信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
一种常用的信号量:二元信号量:只允许一个进程访问资源
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
程序对信号量的操作都是原子的
信号量其实就是一个计数器,fork后会在父子进程中共享,然后通过更改和判断计数器的值,进而来实现不同进程访问共享内存时的同步
7)套接字socket
套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信