进程间通信的五种⽅式
进程间通信的意思就是在不同进程之间传递信息。它是⼀组编程接⼝,让程序员协调不同进程,使能够相互传递消息。
IPC⽬的
1)数据传输:⼀个进程需要将它的数据发送给另⼀个进程,发送的数据量在⼀个字节到⼏兆字节之间。
2)共享数据:多个进程想要操作共享数据,⼀个进程对共享数据的修改,别的进程应该⽴刻看到。
3)通知事件:⼀个进程需要向另⼀个或⼀组进程发送消息,通知它(它们)发⽣了某种事件(如进程终⽌时要通知)。
4)资源共享:多个进程之间共享同样的资源。为了作到这⼀点,需要提供锁和同步机制。
进程通信方式
5)进程控制:有些进程希望完全控制另⼀个进程的执⾏(如Debug进程),此时控制进程希望能够拦截另⼀个进程的所有陷⼊和异常,并能够及时知道它的状态改变。
IPC⽅式包括:管道、系统IPC(信号量、消息队列、共享内存)和套接字(socket)。
管道:
3种。管道是⾯向字节流,⾃带互斥与同步机制,⽣命周期随进程。
1)普通管道PIPE, 通常有两种限制,⼀是半双⼯,数据同时只能单向传输;⼆是只能在⽗⼦或者兄弟进程间使⽤.,
2)命令流管道s_pipe: 去除了第⼀种限制,为全双⼯,可以同时双向传输,
3)命名管道FIFO, 去除了第⼆种限制,可以在许多并不相关的进程之间进⾏通讯。
①⽆名管道:没有磁盘节点,仅仅作为⼀个内存对象,⽤完就销毁了。因此没有显⽰的打开过程,实际在创建时⾃动打开,并且⽣成内存iNode,其内存对象和普通⽂件的⼀致,所以读写操作⽤的同样的接⼝,但是专⽤的。因为不能显式打开(没有任何标⽰),所以只能⽤在⽗⼦进程,兄弟进程,或者其他继承了祖先进程的管道⽂件对象的两个进程间使⽤【具有共同祖先的进程】
int pipe(int fd[2]);//由参数fd返回两个⽂件描述符,fd[0]为读⽽打开  fd[1]为写⽽打开
int read(fd[0], buff, int size);    int write(fd[1], buff, int size);
②有名管道:任意两个或多个进程间通讯。因为它在⽂件⽬录树中有⼀个⽂件标⽰(FIFO) 实际不占据磁盘空间,数据缓存在内存上。它与普通⽂件类似,都遵循打开,读,写,关闭的过程,但读写的内部实现和普通⽂件不同,和⽆名管道⼀样。
命令:mkfifo a=filename  //mkfifo(char *path,int flag)系统调⽤。
标识符与键:每个内核的IPC结构(消息队列、信号量或共享内存)都⽤⼀个⾮负整数标识符引⽤。
标识符是IPC对象的内部名。为了是多个进程间能够访问到同⼀IPC对象,需要提供⼀个外部名。即“键(key)”,键与每个IPC对象关联,并作为对象的外部名。键的数据类型为key_t,由内核变换成标识符。
内核对象:⽤于进程间通讯时,多进程能访问同⼀资源的记录,⽤标识符标识。。
信号量:
1.临界资源:同⼀时刻,只能被⼀个进程访问的资源
2.临界区:访问临界资源的代码区
3.原⼦操作:任何情况下不能被打断的操作。
它是⼀个计数器,记录资源能被多少个进程同时访问。⽤于控制多进程对临界资源的访问(同步)),并且是⾮负值。主要作为进程间以及同⼀进程的不同线程间的同步⼿段。
操作:创建或获取,若是创建必须初始化,否则不⽤初始化。
int semget((key_t)key, int nsems, int flag);//创建或获取信号量
int semop(int semid, stuct sembuf*buf, int length);//加⼀操作(V操作):释放资源;减⼀操作(P操作):获取资源
int semct(int semid, int pos, int cmd);//初始化和删除
注:我们可以封装成库,实现信号量的创建或初始化,p操作,V操作,删除操作。。
消息队列:
消息队列是消息的链表,是存放在内核中并由消息队列标识符标识。因此是随内核持续的,只有在内核重起或者显⽰删除⼀个消息队列时,该消息队列才会真正被删除。。消息队列克服了信号传递信息少,管道只能承载⽆格式字节流以及缓冲区受限等特点。允许不同进程将格式化的数据流以消息队列形式发送给任意进程,对消息队列具有操作权限的进程都可以使⽤msgget完成对消息队列的操作控制,通过使⽤消息类型,进程可以按顺序读信息,或为消息安排优先级顺序。
与信号量相⽐,都以内核对象确保多进程访问同⼀消息队列。但消息队列发送实际数据,信号量进⾏进程同步控制。
与管道相⽐,管道发送的数据没有类型,读取数据端⽆差别从管道中按照前后顺序读取;消息队列有类型,读端可以根据数据类型读取特定的数据。
操作:创建或获取消息队列, int msgget((key_tkey, int flag);//若存在获取,否则创建它
发送消息:int msgsnd(int msgid, void *ptr, size_t size, int flag); ptr指向⼀个结构体存放类型和数据 size 数据的⼤⼩
接受消息:int msgrcv(int msgid, void *ptr, size_t size, long type, int flag);
删除消息队列: int msgctl(int msgid, int cmd, struct msgid_ds*buff);
共享内存:
共享内存就是映射⼀段能被其他进程所访问的内存,这段共享内存由⼀个进程创建,但多个进程都可以访问。
共享内存是最快的⼀种IPC,因为不需要在客户进程和服务器进程之间赋值。使⽤共享内存的唯⼀注意的是是多个进程对⼀给定的存储区的同步访问。【若服务器进程正在向共享存储区写⼊数据,则写完数据之前客户进程不应读取数据,或者客户进程正在从共享内存中读取数据,服务进程不应写⼊数据。。所以我们要对共享内存进⾏同步控制,通常是信号量。】
int shmget((key_t)key, size_t size, int flag); //size 开辟内存空间的⼤⼩,flag:若存在则获取,否则创建共享内存存储段,返回⼀个标识符。
void *shmat(int shmid, void *addr, int flag); //将共享内存段连接到进程的地址空间中,返回⼀个共享内存⾸地址
函数shmat将标识号为shmid共享内存映射到调⽤进程的地址空间中,映射的地址由参数shmaddr和shmflg共同确定,其准则为:
(1) 如果参数shmaddr取值为NULL,系统将⾃动确定共享内存链接到进程空间的⾸地址。
(2) 如果参数shmaddr取值不为NULL且参数shmflg没有指定SHM_RND标志,系统将运⽤地址shmaddr链接共享内存。
(3) 如果参数shmaddr取值不为NULL且参数shmflg指定了SHM_RND标志位,系统将地址shmaddr对齐后链接共享内存。其中选项SHM_RND的意思是取整对齐,常数SHMLBA代表了低边界地址的倍数,公式“shmaddr – (shmaddr % SHMLBA)”的意思是将地址shmaddr移动到低边界地址的整数倍上。
int shmdt(void *ptr); //断开进程与共享内存的链接
进程脱离共享内存区后,数据结构 shmid_ds 中的 shm_nattch 就会减 1 。但是共享段内存依然存在,只有 shm_attch 为 0 后,即没有任何进程再使⽤该共享内存区,共享内存区才在内核中被删除。⼀般来说,当⼀个进程终⽌时,它所附加的共享内存区都会⾃动脱离。
int shmctl(int shmid, int cmd, struct shmid_ds *buff); //删除共享内存(内核对象)
shmid是shmget返回的标识符;
cmd是执⾏的操作:有三种值,⼀般为 IPC_RMID  删除共享内存段;
buff默认为0.
如果共享内存已经与所有访问它的进程断开了连接,则调⽤IPC_RMID⼦命令后,系统将⽴即删除共享内存的标识符,并删除该共享内存区,以及所有相关的数据结构;
如果仍有别的进程与该共享内存保持连接,则调⽤IPC_RMID⼦命令后,该共享内存并不会被⽴即从系统中删除,⽽是被设置为
IPC_PRIVATE状态,并被标记为”已被删除”(使⽤ipcs命令可以看到dest字段);直到已有连接全部断开,该共享内存才会最终从系统中消失。
需要说明的是:⼀旦通过shmctl对共享内存进⾏了删除操作,则该共享内存将不能再接受任何新的连接,即使它依然存在于系统中!所以,可以确知, 在对共享内存删除之后不可能再有新的连接,则执⾏删除操作是安全的;否则,在删除操作之后如仍有新的连接发⽣,则这些连接都将可能失败!
消息队列和管道基本上都是4次拷贝,⽽共享内存(mmap, shmget)只有两次。
4次:1,由⽤户空间的buf中将数据拷贝到内核中。2,内核将数据拷贝到内存中。3,内存到内核。4,内核到⽤户空间的buf.
2次: 1,⽤户空间到内存。 2,内存到⽤户空间。
消息队列、共享内存和管道都是内核对象,所执⾏的操作也都是系统调⽤,⽽这些数据最终是要存储在内存中执⾏的。因此不可避免的要经过4次数据的拷贝。但是共享内存不同,当执⾏mmap或者shmget时,会在内存中开辟空间,然后再将这块空间映射到⽤户进程的虚拟地址空间中,即返回值为⼀个指向逻辑地址的指针。当⽤户使⽤这个指针时,例如赋值操作,会引起⼀个从逻辑地址到物理地址的转化,会将数据直接写⼊对应的物理内存中,省去了拷贝到内核中的过程。当读取数据时,也是类似的过程,因此总共有两次数据拷贝。
socket通信
适合同⼀主机的不同进程间和不同主机的进程间进⾏全双⼯⽹络通信。但并不只是Linux有,在所有提供了TCP/IP协议栈的操作系统中⼏乎都提供了socket,⽽所有这样操作系统,对套接字的编程⽅法⼏乎是完全⼀样的,即“⽹络编程”。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。