linux基础——linux进程间通信(IPC)机制总结

Linux中传统的IPC机制 介绍 IPC全称为Inter-Process Communication,含义为进程间通信,是指两个进程之间进行数据交换的过程。IPC不是Android中所独有的,任何一个操作系统都需要有相应的IPC机制,比如Windows上可以通过剪贴板等进行进程间通信;Linux上可以通过管道(Pipe)、信号(Sinal)、信号量(Semophore)、消息队列(Message)、共享内存(Share Memory)和套接字(Socket)等来进行进程间的通信。可以看到不同的操作系统有着不同IPC机制,对于Andro 阅读详情
原

linux基础——linux进程间通信(IPC)机制总结

      版权声明:本文为博主原创文章,未经博主允许不得转载。          https://blog.youkuaiyun.com/a987073381/article/details/52006729        </div>
        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
                          <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-f57960eb32.css">
      <div class="htmledit_views" id="content_views">
    在linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication),它是多个进程之间相互沟通的一种方法。在linux下有多种进程间通信的方法:半双工管道、命名管道、消息队列、信号、信号量、共享内存、内存映射文件,套接字等等。使用这些机制可以为linux下的网络服务器开发提供灵活而又坚固的框架。

1. 管道 (PIPE)
    管道实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。
管道的特点:
1、管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
2、 只能用于父子进程或者兄弟进程之间( 具有亲缘关系的进程)。 比如fork或exec创建的新进程, 在使用exec创建新进程时,需要将管道的文件描述符作为参数传递给exec创建的新进程。 当父进程与使用fork创建的子进程直接通信时,发送数据的进程关闭读端,接受数据的进程关闭写端。
3、单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
4、数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

管道的实现机制:

    管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。

管道只能在本地计算机中使用,而不可用于网络间的通信。 
pipe函数原型:

  
  1. #include <unistd.h>
  2. int pipe(int file_descriptor[2]); //建立管道,该函数在数组上填上两个新的文件描述符后返回0,失败返回-1。
  3. eg. int fd[ 2]
  4. int result = pipe(fd);
通过使用底层的read和write调用来访问数据。 向 file_descriptor[1]写 数据,从 file_descriptor[0]中 读数据。写入与读取的顺序原则是 先进先出。 
管道读写规则
当没有数据可读时
    O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
    O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
当管道满的时候
    O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
    O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
如果所有管道写端对应的文件描述符被关闭,则read返回0
如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE
当要写入的数据量不大于PIPE_BUF(Posix.1要求PIPE_BUF至少 512字节)时,linux将保证写入的原子性。
当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

2. 命名管道(FIFO)
命名管道是一种特殊类型的文件,它在系统中以文件形式存在。这样克服了管道的弊端,他可以 允许没有亲缘关系的进程间通信。 
创建管道的两个系统调用原型:

  
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. int mkfifo(const char *filename,mode_t mode); //建立一个名字为filename的命名管道,参数mode为该文件的权限(mode%~umask),若成功则返回0,否则返回-1,错误原因存于errno中。
  4. eg.mkfifo( "/tmp/cmd_pipe", S_IFIFO | 0666 );
 具体操作方法只要创建了一个命名管道然后就可以使用open、read、write等系统调用来操作。创建可以手工创建或者程序中创建。 
 

 
  1. int mknod(const char *path, mode_t mode, dev_t dev); //第一个参数表示你要创建的文件的名称,第二个参数表示文件类型,第三个参数表示该文件对应的设备文件的设备号。只有当文件类型为 S_IFCHR 或 S_IFBLK 的时候该文件才有设备号,创建普通文件时传入0即可。
  2. eg.mknod(FIFO_FILE,S_IFIFO| 0666, 0);

管道和命名管道的区别:
对于命名管道FIFO来说,IO操作和普通管道IO操作基本一样,但是两者有一个主要的区别,在命名管道中,管道可以是事先已经创建好的,比如我们在命令行下执行
mkfifo myfifo
就是创建一个命名通道,我们必须用open函数来显示地建立连接到管道的通道,而在管道中,管道已经在主进程里创建好了,然后在fork时直接复制相关数据或者是用exec创建的新进程时把管道的文件描述符当参数传递进去。
一般来说FIFO和PIPE一样总是处于阻塞状态。也就是说如果命名管道FIFO打开时设置了读权限,则读进程将一直阻塞,一直到其他进程打开该FIFO并向管道写入数据。这个阻塞动作反过来也是成立的。如果不希望命名管道操作的时候发生阻塞,可以在open的时候使用O_NONBLOCK标志,以关闭默认的阻塞操作。

3. 信号 (signal)
信号机制是unix系统中最为古老的进程之间的通信机制,用于一个或几个进程之间传递异步信号。信号可以有各种异步事件产生,比如键盘中断等。shell也可以使用信号将作业控制命令传递给它的子进程。
在此列出几个简单使用方法定义: 

  
  1. #include <sys/types.h>
  2. #include <signal.h>
  3. void (*signal( int sig, void (*func)( int)))( int); //用于截取系统信号,第一个参数为信号,第二个参数为对此信号挂接用户自己的处理函数指针。返回值为以前信号处理程序的指针。
  4. eg. int ret = signal(SIGSTOP, sig_handle);
 由于signal不够健壮,推荐使用sigaction函数。
 
 

  
  1. int kill(pid_t pid,int sig); //kill函数向进程号为pid的进程发送信号,信号值为sig。当pid为0时,向当前系统的所有进程发送信号sig。
  2. int raise(int sig); //向当前进程中自举一个信号sig, 即向当前进程发送信号。
  3. #include <unistd.h>
  4. unsigned int alarm(unsigned int seconds); //alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。使用alarm函数的时候要注意alarm函数的覆盖性,即在一个进程中采用一次alarm函数则该进程之前的alarm函数将失效。
  5. int pause(void); //使调用进程(或线程)睡眠状态,直到接收到信号,要么终止,或导致它调用一个信号捕获函数。
 

4. 消息队列(Message queues)
消息队列是内核地址空间中的内部链表,通过linux内核在各个进程直接传递内容,消息顺序地发送到消息队列中,并以几种不同的方式从队列中获得,每个消息队列可以用 IPC标识符 唯一地进行识别。内核中的消息队列是通过IPC的标识符来区别,不同的消息队列直接是相互独立的。每个消息队列中的消息,又构成一个 独立的链表。
消息队列克服了信号承载信息量少,管道只能承载无格式字符流。 
消息队列头文件: 

  
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <sys/msg.h>
 
1、 消息缓冲区结构:

 
  1. struct msgbuf{
  2. long mtype;
  3. char mtext[ 1]; //柔性数组
  4. }
 
在结构中有两个成员,mtype为消息类型,用户可以给某个消息设定一个类型,可以在消息队列中正确地发送和接受自己的消息。mtext为消息数据,采用柔性数组,用户可以重新定义msgbuf结构。例如:

  
  1. struct msgbuf{
  2. long mtype;
  3. char mtext[ 1]; //柔性数组
  4. }
 
 
当然用户不可随意定义msgbuf结构,因为在linux中消息的大小是有限制的,在linux/msg.h中定义如下:
#define MSGMAX 8192
消息总的大小不能超过8192个字节,包括mtype成员(4个字节)。
2、msqid_ds内核数据结构。
<div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">struct msgid_ds{</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">   struct ipc_perm msg_perm{</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">   time_t msg_stime;</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">   time_t msg_rtime;</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">   time_t msg_ctime;</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">   unsigned long _msg_cbuyes;</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">    ..........</div><div style="font-family: 微软雅黑; font-size: 14px; line-height: 21px;">   };</div>
 
 
Linux内核中,每个消息队列都维护一个结构体,此结构体保存着消息队列当前状态信息,该结构体在头文件linux/msg.h中定义。
3、ipc_perm内核数据结构

 
  1. struct ipc_perm{
  2. key_t key;
  3. uid_t uid;
  4. gid_t gid;
  5. .......
  6. };
 
 
结构体ipc_perm保存着消息队列的一些重要的信息,比如说消息队列关联的键值,消息队列的用户id组id等。它定义在头文件linux/ipc.h中。
常用函数:
系统建立IPC通讯 (消息队列、信号量和共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。 

  
  1. key_t ftok( const char * fname, int id ); //参数一为目录名称, 参数二为id。如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
  2. eg. key_t key = key =ftok( ".", 1);
  3. int msgget(key_t key,int msgflag); //msgget用来创建和访问一个消息队列。程序必须提供一个键值来命名特定的消息队列。
  4. eg. int msg_id = msgget(key, IPC_CREATE | IPC_EXCL | 0x0666); //根据关键字创建一个新的队列(IPC_CREATE),如果队列存在则出错(IPC_EXCL),拥有对文件的读写执行权限(0666)。
  5. int msgsnd(int msgid,const void *msgptr,size_t msg_sz,int msgflg); //msgsnd函数允许我们把一条消息添加到消息队列中。msgptr只想准备发送消息的指针,指针结构体必须以一个长整型变量开始。
  6. eg.struct msgmbuf{
  7. int mtype;
  8. char mtext[ 10];
  9. };
  10. struct msgmbuf msg_mbuf;
  11. msg_mbuf.mtype = 10; //消息大小10字节
  12. memcpy(msg_mbuf.mtext, "测试消息", sizeof( "测试消息"));
  13. int ret = msgsnd(msg_id, &msg_mbuf, sizeof( "测试消息"), IPC_NOWAIT);
  14. int msgrcv(int msgid, void *msgptr, size_t msg_sz, long int msgtype, int msgflg); //msgrcv可以通过msqid对指定消息队列进行接收操作。第二个参数为消息缓冲区变量地址,第三个参数为消息缓冲区结构大小,但是不包括mtype成员长度,第四个参数为mtype指定从队列中获取的消息类型。
  15. eg. int ret = msgrcv(msg_id, &msg_mbuf, 10, 10, IPC_NOWAIT | MSG_NOERROR);
  16. int msgctl(int msqid,int cmd,struct msqid_ds *buf); //msgctl函数主要是一些控制如删除消息队列等操作。 cmd值如下:
  17. IPC_STAT:获取队列的msgid_ds结构,并把它存到buf指向的地址。
  18. IPC_SET:将队列的msgid_ds设置为buf指向的msgid_ds。
  19. IPC_RMID:内核删除消息队列,最后一项填 NULL, 执行操作后,内核会把消息队列从系统中删除。
消息队列的本质
Linux的消息队列(queue)实质上是一个链表,它有消息队列标识符(queue ID)。 msgget创建一个新队列或打开一个存在的队列;msgsnd向队列末端添加一条新消息;msgrcv从队列中取消息, 取消息是不一定遵循先进先出的, 也可以按消息的类型字段取消息。

消息队列与命名管道的比较
消息队列跟命名管道有不少的相同之处,通过与命名管道一样,消息队列进行通信的进程可以是不相关的进程,同时它们都是通过发送和接收的方式来传递数据的。在命名管道中,发送数据用write,接收数据用read,则在消息队列中,发送数据用msgsnd,接收数据用msgrcv。而且它们对每个数据都有一个最大长度的限制。
与命名管道相比,消息队列的优势在于,1、消息队列也可以独立于发送和接收进程而存在,从而消除了在同步命名管道的打开和关闭时可能产生的困难。2、同时通过发送消息还可以避免命名管道的同步和阻塞问题,不需要由进程自己来提供同步方法。3、接收程序可以通过消息类型有选择地接收数据,而不是像命名管道中那样,只能默认地接收。

5. 信号量(Semaphore)
信号量是一种计数器,用于控制对多个进程共享的资源进行的访问。它们常常被用作一个锁机制,在某个进程正在对特定的资源进行操作时,信号量可以防止另一个进程去访问它。 
信号量是特殊的变量,它只取正整数值并且只允许对这个值进行两种操作:等待(wait)和信号(signal)。(P、V操作,P用于等待,V用于信号) 
p(sv):如果sv的值大于0,就给它减1;如果它的值等于0,就挂起该进程的执行 
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行;如果没有其他进程因等待sv而挂起,则给它加1 
简单理解就是P相当于申请资源,V相当于释放资源 
信号量头文件: 

    
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <sys/sem.h>
 
  
内核为每个信号量集合都维护一个semid_ds结构:

     
  1. struct semid_ds{
  2. struct ipc_perm sem_perm;
  3. unsigned short sem_nsems;
  4. time_t sem_otime;
  5. time_t sem_ctime;
  6. ...
  7. }
信号量数据结构:

    
  1. union semun{
  2. int val;
  3. struct semid_ds *buf;
  4. unsigned short * array;
  5. struct seminfo *__buf;
  6. }
 信号量操作sembuf结构:
  

    
  1. struct sembuf{
  2. ushort sem_num; //信号量的编号
  3. short sem_op; //信号量的操作。如果为正,则从信号量中加上一个值,如果为负,则从信号量中减掉一个值,如果为0,则将进程设置为睡眠状态,直到信号量的值为0为止。
  4. short sem_flg; //信号的操作标志,一般为IPC_NOWAIT。
  5. }
 常用函数:
  

    
  1. int semget(key_t key, int num_sems, int sem_flags); //semget函数用于创建一个新的信号量集合 , 或者访问一个现有的集合(不同进程只要key值相同即可访问同一信号量集合)。第一个参数key是ftok生成的键值,第二个参数num_sems可以指定在新的集合应该创建的信号量的数目,第三个参数sem_flags是打开信号量的方式。
  2. eg. int semid = semget(key, 0, IPC_CREATE | IPC_EXCL | 0666); //第三个参数参考消息队列int msgget(key_t key,int msgflag);第二个参数。
  3. int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops); //semop函数用于改变信号量的值。第二个参数是要在信号集合上执行操作的一个数组,第三个参数是该数组操作的个数 。
  4. eg.struct sembuf sops = { 0, + 1, IPC_NOWAIT}; //对索引值为0的信号量加一。
  5. semop(semid, &sops, 1); //以上功能执行的次数为一次。
  6. int semctl(int sem_id, int sem_num, int command,...); //semctl函数用于信号量集合执行控制操作,初始化信号量的值,删除一个信号量等。 类似于调用msgctl(), msgctl()是用于消息队列上的操作。第一个参数是指定的信号量集合(semget的返回值),第二个参数是要执行操作的信号量在集合中的索引值(例如集合中第一个信号量下标为0),第三个command参数代表要在集合上执行的命令。
  7. IPC_STAT:获取某个集合的semid_ds结构,并把它存储到semun联合体的buf参数指向的地址。
  8. IPC_SET:将某个集合的semid_ds结构的ipc_perm成员的值。该命令所取的值是从semun联合体的buf参数中取到。
  9. IPC_RMID:内核删除该信号量集合。
  10. GETVAL:返回集合中某个信号量的值。
  11. SETVAL:把集合中单个信号量的值设置成为联合体val成员的值。

6. 共享内存(Share Memory)
共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的地址空间(这里的地址空间具体是哪个地方?)中。其他进程可以将 同一段共享内存连接到自己的地址空间中。所有进程都可以访问共享内存中的地址,就好像它们是malloc分配的一样。如果一个进程向共享内存中写入了数据,所做的改动将立刻被其他进程看到。 
共享内存是 IPC最快捷的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式则是需要将数据通过中间机制进行转换。共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅映射到各进程的地址不同而已,因此不需要进行复制,可以直接使用此段空间。
注意:共享内存本身并没有同步机制,需要程序员自己控制。 
  共享内存头文件:

    
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <sys/shm.h>
结构shmid_ds结构体(是不是很眼熟,看消息队列的 msgid_ds结构体):

   
  1. strcut shmid_ds{
  2. struct ipc_perm shm_perm;
  3. size_t shm_segsz;
  4. time_t shm_atime;
  5. time_t shm_dtime;
  6. ......
  7. }
共享内存函数定义:

   
  1. int shmget(key_t key,size_t size,int shmflg); //shmget函数用来创建一个新的共享内存段, 或者访问一个现有的共享内存段(不同进程只要key值相同即可访问同一共享内存段)。第一个参数key是ftok生成的键值,第二个参数size为共享内存的大小,第三个参数sem_flags是打开共享内存的方式。
  2. eg. int shmid = shmget(key, 1024, IPC_CREATE | IPC_EXCL | 0666); //第三个参数参考消息队列int msgget(key_t key,int msgflag);
  3. void *shmat(int shm_id,const void *shm_addr,int shmflg); //shmat函数通过shm_id将共享内存连接到进程的地址空间中。第二个参数可以由用户指定共享内存映射到进程空间的地址,shm_addr如果为0,则由内核试着查找一个未映射的区域。返回值为共享内存映射的地址。
  4. eg. char *shms = ( char *)shmat(shmid, 0, 0); //shmid由shmget获得
  5. int shmdt(const void *shm_addr); //shmdt函数将共享内存从当前进程中分离。 参数为共享内存映射的地址。
  6. eg.shmdt(shms);
  7. int shmctl(int shm_id,int cmd,struct shmid_ds *buf); //shmctl函数是控制函数,使用方法和消息队列msgctl()函数调用完全类似。参数一shm_id是共享内存的句柄,cmd是向共享内存发送的命令,最后一个参数buf是向共享内存发送命令的参数。

消息队列、信号量以及共享内存的相似之处:
它们被统称为XSI IPC,它们在内核中有相似的IPC结构(消息队列的msgid_ds,信号量的semid_ds,共享内存的shmid_ds),而且都用一个非负整数的标识符加以引用(消息队列的msg_id,信号量的sem_id,共享内存的shm_id,分别通过msgget、semget以及shmget获得),标志符是IPC对象的内部名,每个IPC对象都有一个键(key_t key)相关联,将这个键作为该对象的外部名。

XSI IPC和PIPE、FIFO的区别:
1、XSI IPC的IPC结构是在系统范围内起作用,没用使用引用计数。如果一个进程创建一个消息队列,并在消息队列中放入几个消息,进程终止后,即使现在已经没有程序使用该消息队列,消息队列及其内容依然保留。而PIPE在最后一个引用管道的进程终止时,管道就被完全删除了。对于FIFO最后一个引用FIFO的进程终止时,虽然FIFO还在系统,但是其中的内容会被删除。
2、和PIPE、FIFO不一样,XSI IPC不使用文件描述符,所以不能用ls查看IPC对象,不能用rm命令删除,不能用chmod命令删除它们的访问权限。只能使用ipcs和ipcrm来查看可以删除它们。

7. 内存映射(Memory Map)
内存映射文件,是由一个文件到一块内存的映射。内存映射文件与 虚拟内存有些类似,通过内存映射文件可以保留一个地址的区域,
同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作。 每一个使用该机制的进程通过把同一个共享的文件映射到自己的进程地址空间来实现多个进程间的通信(这里类似于共享内存,只要有一个进程对这块映射文件的内存进行操作,其他进程也能够马上看到)。
使用内存映射文件不仅可以实现多个进程间的通信,还可以用于 处理大文件提高效率。因为我们普通的做法是 把磁盘上的文件先拷贝到内核空间的一个缓冲区再拷贝到用户空间(内存),用户修改后再将这些数据拷贝到缓冲区再拷贝到磁盘文件,一共四次拷贝。如果文件数据量很大,拷贝的开销是非常大的。那么问题来了,系统在在进行内存映射文件就不需要数据拷贝?mmap()确实没有进行数据拷贝,真正的拷贝是在在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行一次数据拷贝。效率高于read/write。
内存映射头文件:

    
  1. #include <sys.mman.h>
  2. void *mmap(void*start,size_t length,int prot,int flags,int fd,off_t offset); //mmap函数将一个文件或者其它对象映射进内存。 第一个参数为映射区的开始地址,设置为0表示由系统决定映射区的起始地址,第二个参数为映射的长度,第三个参数为期望的内存保护标志,第四个参数是指定映射对象的类型,第五个参数为文件描述符(指明要映射的文件),第六个参数是被映射对象内容的起点。成功返回被映射区的指针,失败返回MAP_FAILED[其值为(void *)-1]。
  3. int munmap(void* start,size_t length); //munmap函数用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。如果解除映射成功则返回0,否则返回-1,错误原因存于errno中错误代码EINVAL。
  4. int msync(void *addr,size_t len,int flags); //msync函数实现磁盘文件内容和共享内存取内容一致,即同步。第一个参数为文件映射到进程空间的地址,第二个参数为映射空间的大小,第三个参数为刷新的参数设置。

共享内存和内存映射文件的区别:
内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就像操作进程空间里的地址一样了,比如使用c语言的memcpy等内存操作的函数。这种方法能够很好的应用在需要频繁处理一个文件或者是一个大文件的场合,这种方式处理IO效率比普通IO效率要高
  共享内存是内存映射文件的一种特殊情况,内存映射的是一块内存,而非磁盘上的文件。共享内存的主语是进程(Process),操作系统默认会给每一个进程分配一个内存空间,每一个进程只允许访问操作系统分配给它的哪一段内存,而不能访问其他进程的。而有时候需要在不同进程之间访问同一段内存,怎么办呢?操作系统给出了 创建访问共享内存的API,需要共享内存的进程可以通过这一组定义好的API来访问多个进程之间共有的内存,各个进程访问这一段内存就像访问一个硬盘上的文件一样。

内存映射文件与虚拟内存的区别和联系:
内存映射文件和虚拟内存都是操作系统内存管理的重要部分,两者有相似点也有不同点。
联系:虚拟内存和内存映射都是将一部分内容加载到内存,另一部放在磁盘上的一种机制。对于用户而言都是透明的。
区别:虚拟内存是硬盘的一部分,是内存和硬盘的数据交换区,许多程序运行过程中把暂时不用的程序数据放入这块虚拟内存,节约内存资源。内存映射是一个文件到一块内存的映射,这样程序通过内存指针就可以对文件进行访问。
虚拟内存的硬件基础是分页机制。另外一个基础就是局部性原理(时间局部性和空间局部性),这样就可以将程序的一部分装入内存,其余部分留在外存,当访问信息不存在,再将所需数据调入内存。而内存映射文件并不是局部性,而是使虚拟地址空间的某个区域银蛇磁盘的全部或部分内容,通过该区域对被映射的磁盘文件进行访问,不必进行文件I/O也不需要对文件内容进行缓冲处理。

8. 套接字 
套接字机制不但可以单机的不同进程通信,而且使得跨网机器间进程可以通信。 
套接字的创建和使用与管道是有区别的,套接字 明确地将客户端与服务器 区分开来,可以实现多个客户端连到同一服务器。 
服务器套接字连接过程描述: 
首先,服务器应用程序用socket创建一个套接字,它是系统分配服务器进程的类似文件描述符的资源。 接着,服务器调用bind给套接字命名。这个名字是一个标示符,它允许linux将进入的针对特定端口的连接转到正确的服务器进程。 然后,系统调用listen函数开始接听,等待客户端连接。listen创建一个队列并将其用于存放来自客户端的进入连接。 当客户端调用connect请求连接时,服务器调用accept接受客户端连接,accept此时会创建一个新套接字,用于与这个客户端进行通信。 
客户端套接字连接过程描述: 
客户端首先调用socket创建一个未命名套接字,让后将服务器的命名套接字作为地址来调用connect与服务器建立连接。 
只要双方连接建立成功,我们就可以像操作底层文件一样来操作socket套接字实现通信。 
几个基础函数定义: 

    
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. int socket(it domain,int type,int protocal);
  4. int bind(int socket,const struct sockaddr *address,size_t address_len);
  5. int listen(int socket,int backlog);
  6. int accept(int socket,struct sockaddr *address,size_t *address_len);
  7. int connect(int socket,const struct sockaddr *addrsss,size_t address_len);
详细请看: http://blog.youkuaiyun.com/a987073381/article/details/51869000
还记得消息队列中的msgbuf结构吗?在socket编程中也同样适用,在socket编程中,一个服务可以接受多个客户端的连接,可以为每个客户端设定一个消息类型,服务器和客户端直接的通信可以通过此消息类型来发送和接受消息,而且多个客户端之间也可以通过消息类型来区分。

参考:
《linux网络编程》
《unix环境高级编程》

深入解析Linux进程间通信:IPC机制与应用场景全方位解读 进程间通信指的是不同进程之间如何交换数据、同步或共享资源。在操作系统中,进程相互独立、拥有各自的内存空间,因此进程间的通信需要借助操作系统提供的特定机制来完成。 阅读详情

相关推荐

C语言_Linux 进程间通信(IPC)机制详解

C语言_Linux 进程间通信(IPC)机制详解

renhl252的专栏 511

Linux进程间通信(Linux IPC)

在Linux下由很多种进程间通信的方式,在下面主要介绍七种,分别是:匿名管道(PIPE)、命名管道(FIFO)、信号、共享内存映射、共享内存、消息队列、信号量、UNIX域套接字。

Peerless__的博客 7668

GEO芯片数据下载和探针ID转换(保姆级教程)

R语言安装、GEO芯片数据下载、探针ID转换

qq_43138237的博客 3万+

LINUX---进程间通信(IPC)

通信

weixin_48651223的博客 3493

Mid-360与FAST-LIO2实战:从点云采集到高精度建图全流程解析

本文详细解析了使用Livox Mid-360激光雷达与FAST-LIO2算法实现高精度实时建图的全流程。内容涵盖硬件准备、软件环境搭建、算法部署配置、数据采集实战,并重点探讨了多楼层场景下的参数调优与误差抑制策略,为机器人及无人机三维感知应用提供了实用指南。

prometheus9mon的博客 412

Lora无线温湿度传感器方案

综上所述,Lora无线温湿度传感器以其长距离传输、低功耗、高稳定性、精准测量、无线传输以及广泛的应用场景等特点,在环境监测领域展现出了强大的竞争力和广泛的应用前景。Lora无线温湿度传感器广泛应用于各种需要远程监控和数据采集的场景,如仓储、农业、机房、楼宇、交通、工业、矿产、电力等领域。Lora无线温湿度传感器是一种采用Lora无线通信技术进行数据传输的温湿度监测设备。四、产品参数(以某款工业级Lora温湿度传感器为例)

weixin_46632654的博客 757

Linux IPC解析:匿名命名管道与共享内存

进程间通信)是计算机系统中不同进程之间交换数据和同步操作的机制。由于现代计算机系统中,程序通常会由多个进程组成,这些进程可能需要相互通信以完成任务,因此IPC非常重要。数据交换:允许不同进程共享数据或传递信息。同步:协调多个进程之间的操作,以避免竞态条件和资源冲突。互斥:控制多个进程对共享资源的访问,确保同一时间只有一个进程能够访问资源管道(Pipes):匿名管道:用于相关进程之间的单向通信,如父子进程或兄弟进程。

喜欢就坚持吧 2075

导数在工程与AI中的12个实战应用解析

导数作为数学中的基本概念,本质是描述变化率的工具,其核心价值在于将非线性问题局部线性化处理。从原理上看,通过极限过程捕捉函数瞬时变化特性,使工程师能精确控制系统动态行为,帮助科学家量化自然规律变化速率。在技术实现层面,现代符号计算(如Mathematica)、数值计算(如MATLAB)和自动微分(如PyTorch)工具链的发展,大幅提升了导数计算的效率与精度。典型应用场景涵盖机械控制(如ABS防抱死系统)、金融工程(如期权希腊值计算)、医疗影像(如Canny边缘检测)等领域。特别在机器学习中,反向传播算法依

weixin_35509395的博客 316

简析Linux IPC

无名管道:速度慢,容量有限,只有父子进程能通讯有名管道:任何进程间都能通讯,速度慢信号:实现异步的软中断共享内存:能够很容易控制容量,速度快,但要注意同步问题信号灯集:不能传递复杂消息,只能用来同步。用于实现进程间的互斥与同步,而不是用于存储进程间通信数据消息队列:容量受到系统限制,要注意读的时候,要考虑上一次没有读完数据的问题。

weixin_43902324的博客 588

ERDAS 2022与ArcGIS共存安装教程:如何避免端口冲突(详细配置步骤)

本文提供了一份详细的ERDAS 2022与ArcGIS共存安装教程,核心在于解决两者因FlexNet许可证服务器导致的端口冲突问题。通过分步指导,包括检查现有端口占用、修改ERDAS许可证文件端口号、配置防火墙及客户端设置,确保两款专业GIS与遥感软件能在同一系统上稳定运行。

weixin_29279047的博客 253

药物不良反应预测实战指南:从FAERS数据挖掘到PyTorch深度学习模型(含可解释性分析)

【代码】药物不良反应预测实战指南:从FAERS数据挖掘到PyTorch深度学习模型(含可解释性分析)

理论都是虚的,代码才是王道。 721

Linux 进程间通信-IPC 机制

Linux 平台上在 Kernel 协调下完成进程之间的相互通信,有多种进程间通信 —— Inter Process Communication(IPC)方式。 1. IPC 分类 按照功能用途来看有三种基本的进程间通信类型,分别用户信息交换(Communication),同步(Synchronization)和信号(Signal)。另外,在基本的 IPC 通信机制之上还存在更为复杂和广泛应用的进程间通信机制,通常提供了丰富和更高层次的封装以便于应用开发,比如 Android 平台采用的 Binder

Hugo的博客 2184

linux cma alloc fail 问题分析

摘要:日志显示CMA连续内存分配失败(错误码-ENOMEM),请求128页(512KB)内存时因CMA区域不足或内存碎片导致失败。分析发现系统CMA总内存131072KB,空闲65536KB。解决方案包括:1)手动触发内存碎片整理;2)修改设备树或内核配置增大CMA区域(如从16MB增至20MB)。通过调整CONFIG_CMA_SIZE_MBYTES或设备树中的size参数可解决该问题。

陌上花开缓缓归以的博客 796

Linux进程间通信的秘密通道:IPC机制详解

在 Linux 操作系统中,进程是操作系统的基本运行单位。由于进程间具有独立的地址空间,如何实现进程之间的数据交换和同步成为系统设计中的一个核心问题。为了解决这一问题,Linux 提供了多种进程间通信(Inter-Process Communication, IPC)机制。这些机制在性能、适用场景和复杂性方面各具特点,开发者可以根据具体需求选择合适的通信方式。 本文将从概念出发,详细讲解 Linux 的 IPC 机制,包括管道、消息队列、共享内存、信号量和信号等,帮助读者深入理解 IPC 的原理和应用场景

fudaihb的博客 1032

万字长文介绍ARINC 653,以及在综合模块化航空电子设备(IMA)中的作用

ARINC 653 在综合模块化航空电子设备(IMA)的发展进程中扮演着极为关键的角色。从行业应用的实际情况来看,空客 A380 和波音 787 等先进飞机的航电系统套件充分体现了行业对 IMA 的高度重视和积极投入。在 IMA 架构下,核心软件具备强大的能力,能够支持多个航空电子应用程序的同时运行。这些应用程序可以并行开发,并高效地部署在同一个计算平台上,极大地提高了开发效率和系统集成度。ARINC 653 的出现为航空电子行业创造了一个充满活力和竞争力的商业环境。

2956

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Linux进程间通信_IPC机制

刚开始接触IPC机制时,感觉这个知识点真的时晦涩难懂,因此自己将自己对IPC机制的理解做下总结。 Linux中的IPC机制:信号量, 共享内存, 消息队列。 注意这里的IPC机制的通信只能在一台主机上的多个进程线程之间进行通信,而跨主机之间的通信用socket, poll, epoll机制。 一:信号量     计数信号量,其值在0和某个限制值之间,该值最大为32767, 这里信号量的

xixihaha331的博客 1857

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Linux进程间通信机制IPC

Linux进程间通信机制IPC     Linux IPC机制主要有: 信号量信号管道(有名管道和无名管道)共享内存(效率最高)消息队列Socket网络编程(不同主机间进程的通信)     以下摘录一些很早的文章,讲的蛮清晰的: 深刻理解Linux进程间通

success041000的专栏 1171

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Linux -- 进程间通信(IPC)机制

Linux系统的IPC方式有如下几种: pipe管道 它是unix系统中最古老的IPC形式,所有的UNIX系统都提供此种通信机制,它有以下两种局限性: (1)半双工。现在,虽然某些系统提供了全双工的管道,但是为了可移植性,我们绝不能假定系统支持全双工管道。 (2)管道只能在具有公共祖先的两个进程之间使用。通常,一个管道由一个进程创建,在进程调用fork后,这个管道就能在父子进程之间使用了。 FIF...

程序猿Ricky的日常干货 522

linux进程间通信(IPC)机制总结

转载:linux基础——linux进程间通信(IPC)机制总结_千里之行,始于足下-优快云博客_linux 进程间通信

228

linux进程间通信(IPC)机制总结

在linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication),它是多个进程之间相互沟通的一种方法。在linux下有多种进程间通信的方法:半双工管道、命名管道、消息队列、信号、信号量、共享内存、内存映射文件,套接字等等。使用这些机制可以为linux下的网络服务器开发提供灵活而又坚固的框架。 1. 管道 (PIPE)     管道实际是用于进程间

有趣的人生 一半是山川湖海 一半是初心情怀 5172

嵌入式Linux进程间通信(IPC)机制详解

进程间通信(IPC)是操作系统实现多进程协作的基础技术,其核心原理是通过内核提供的机制打破进程间的隔离性。在Linux系统中,IPC机制主要包括共享内存、消息队列、管道、信号量、信号和UNIX域套接字等,每种方式在传输效率、同步机制和应用场景上各有特点。从技术实现来看,共享内存通过内存映射实现零拷贝通信,性能最高但需要配合信号量同步;消息队列支持结构化数据传输和优先级控制;UNIX域套接字则提供了类似网络套接字的编程接口。在嵌入式系统开发中,合理选择IPC机制对系统性能影响显著,如大数据传输推荐共享内存+信

weixin_30476025的博客 597

深入解析Linux进程间通信(IPC):机制、应用与最佳实践

从管道到eBPF,Linux IPC的演进史正是一部计算机系统设计哲学的发展史。选择何种通信方式,本质上是在数据一致性性能需求和系统复杂度之间寻找平衡点。理解每种机制背后的设计取舍,方能打造出优雅高效的系统架构。

2301_76794365的博客 642

进程间通信效率最高的是_Linux进程间通信:IPC通信机制简述

图控大叔构图传递思想阅读从未如此简单!!!01前言 继续跟着之前推文的步骤,继续分享与Linux进程间通信方式相关的推文,本次的推文内容是IPC通信机制的简述。02什么是IPCIPC内核当中为了增强进程与进程之间数据交互及效率的一种机制的对象英文名Inter Process Communication中文名进程间通信03IPC包含什么?2,IPC里面有什么: 1、消息队列:...

weixin_39721009的博客 748

Linux进程间通信(IPC)机制深度解析与实践指南

本文深入探讨Linux系统中的进程间通信(IPC)机制,包括匿名管道、命名管道(FIFO)、消息队列、共享内存、信号量和套接字等多种方式。通过详细的代码示例解析每种IPC机制的工作原理和实现方法,如使用pipe()创建匿名管道、mkfifo()创建命名管道、msgget()操作消息队列等。文章还介绍了IPC缓冲区管理策略和性能优化技巧,帮助开发者根据实际场景选择合适的通信方式,构建高效可靠的多进程系统。

weixin_71604156的博客 865

【Linux】进程间通信的秘密通道:IPC机制详解

进程间通信(IPC)是操作系统中不同进程之间交换数据和信息的方式。由于每个进程都有独立的内存空间,无法直接访问其他进程的资源,因此需要通过IPC机制实现数据共享。

谁在夜里看海.的博客 5177
上一篇: 计算机中减法的实现原理
下一篇: IPC(进程间通信方式的介绍)
csshuke
博客等级 码龄16年 1517粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值