用管道消息队列共享内存实现进程间通信

一、进程间通信的目的

因为进程的地址空间都是相互独立的,为了实现进程间的数据传输、资源共享、进程控制(如gdb调试)、通知事件等

二、进程间通信的方式

进程间通信的方式有非常多种,本文仅介绍管道中的匿名管道和命名管道和system V中的消息队列共享内存

2.1管道

内核中的一块缓存,两个用户态通过这段内核态的缓存进行数据传输

匿名管道:使用int pipe(int pipefd[2]);pipefd[0]表示读端,pipefd[1]表示写端,成功返回0失败返回-1,适当的设置错误码。

用两个进程通过管道实现进程间通信,子进程向管道内写入,父进程读出,因此子进程可以关闭读端,父进程可以关闭写端。

读操作使用ssize_t read(int fd, void *buf, size_t count);fd表示要从哪个文件描述符中读取,buf时向哪个缓冲区中放读取出的内容,count为要读多少个字节,成功时返回读到的字节数,失败时返回-1,返回0表示已经读到末尾或者没有可读的文件

写操作使用ssize_t write(int fd, const void *buf, size_t count);buf所指的内存中写count个到指定文件描述符fd的文件中。

  1 #include <stdio.h>                                                                                                   
  2 #include <unistd.h>                                                                                                  
  3 #include <stdlib.h>                                                                                                  
  4 #include <string.h>                                                                                                  
  5                                                                                                                      
  6                                                                                                                      
  7 int main()                                                                                                           
  8 {                                                                                                                    
  9   int fds[2];                                                                                                        
 10   if(pipe(fds) == -1)                                                                                                
 11     perror("pipe"),exit(1);                                                                                          
 12   pid_t pid = fork();                                                                                                
 13   if(pid == -1)                                                                                                      
 14   {                                                                                                                  
 15     perror("fork"),exit(1);                                                                                          
 16   }                                                                                                                  
 17   if(pid == 0)                                                                                                       
 18   {                                                                                                                  
 19     sleep(1);  
 20     //子进程,关闭读端                                                                                               
 21     close(fds[0]);                                                                                                   
 22     write(fds[1],"abs",3);                                                                                           
 23     close(fds[1]);                                                                                                   
 24     exit(0);                                                                                                         
 25   }                                                                                                                  
 26   else{                                                                                                              
 27     //父进程                                                                                                         
 28     close(fds[1]);                                                                                                   
 29     char buf[100] = {};                                                                                              
 30      int r = read(fds[0],buf,100);//一直阻塞直到子进程的write写入                                                    
 31      if(r == 0)                                                                                                      
 32        printf("read EOF\n");                                                                                         
 33      else if(r == -1)                                                                                                
 34      {                                                                                                               
 35        perror("read"),exit(1);                                                                                       
 36      }                                                                                                               
 37      else if(r > 0)   
 38      {                                                                                                               
 39        printf("buf= [%s]\n",buf);                                                                                    
 40      }                                                                                                               
 41      close(fds[0]);                                                                                                  
 42        exit(0);                                                                                                      
 43        //内核中的空间自己回收                                                                                        
 44   }                                                                                                                  
 45 }                      

 

命名管道:

创建两个命名管道,使用函数int mkfifo[const char *filename,mode_t mode];第一个参数filename为文件名,第二个参数为文件的权限。

创建成功后使用open函数打开管道int open(const char *pathname, int flags, mode_t mode);pathname:打开文件的路径名flags:用来控制打开文件的模式常见的有O_WRONLY写模式O_CREAT创建模式O_RDONLY读模式mode:用来设置创建文件的权限(rwx),当flags中带有O_CREAT时才有效。成功时返回文件描述符,错误时返回-1.

管道的特点:只能用于具有亲缘关系的进程之间的通信;一般而言进程退出,管道就会随之释放,管道的生命周期随进程;管道是半双工的,数据只能单向流动故双方通信时需要建立两个管道。

2.2system V IPC

消息队列:

在内核中消息队列就是一个结构体:

int msgget(key_t key, int msgflg)打开或创建消息队列//key相当于文件名的整数;flag创建队列用选项IPC_CREAT 加权限 | 0644 创建失败返回-1;打开flag用0返回值消息队列的ID,相对于文件描述符

msgctl()释放内核中的消息队列,如不主动释放,进程结束或操作系统关机会一直存在。

msgsnd()消息队列放数据int msgsnd(int msqid,const void *msgp,size_t len,int flag)//msgid是msgget的返回值;msgp指针要发送的消息在哪里?&mb,用结构体struct msgbuf{long channel;//消息类型(通道号,必须>=1);后面都随便};;len消息的字节数(不包括channel的大小),flag 是0达到上限时消息队列就阻塞在这,等被读走了才能放进去;成功返回0,失败返回-1;

msgrcv()消息队列取数据ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)第一个参数为已打开的消息队列,第二个参数将消息装在哪里,第三个参数不包括消息类型的消息大小(真正接受数据的地方的大小定义的1000就写1000,不是已经接受了多少的数据)取msgtyp通道号为几的数据

const void *msgp,要发送的消息在哪 size_t msgsz,消息的字节数不包括结构体中len,int msgflg);//0必须先定义一个结构体struct msgbuf {long channel;//消息类型(通道号),必须>=1后面的随便定义类型};

删除IPC对象ipcrm 删除用-Q key

ipcs 查看所有systemV的对象(消息队列、共享内存、信号量)都可以显示,只显示消息队列用-q

每个系统中最大创建多少个消息队列MSGMNI cat/proc/sys/kernal/msgmni

每个消息队列中最多能有多少字节MSGMAX cat/proc/sys/kernal/msgmax

  1 #include <stdio.h>                                                                                                   
  2 #include <sys/ipc.h>                                                                                                 
  3 #include <sys/msg.h>                                                                                                 
  4 #include <stdlib.h>                                                                                                  
  5 int main()                                                                                                           
  6 {                                                                                                                    
  7   int ret = msgget(1234,IPC_CREAT|0644);                                                                             
  8   if(ret == -1)                                                                                                      
  9   {                                                                                                                  
 10     perror("msgget \n");                                                                                             
 11     exit(-1);                                                                                                        
 12   }                                                                                                                  
 13   else                                                                                                               
 14   {                                                                                                                  
 15   printf("创建成功\n");                                                                                              
 16   }                                                                                                                  
 17   return 0;                                                                                                          
 18 }                                                                                                                    
 19 

使用消息队列来实现一个客户端发送数据服务器读取数据

    1 #include <stdio.h>                                                                                                 
    2 #include <stdlib.h>                                                                                                
    3 #include <sys/ipc.h>                                                                                               
    4 #include <sys/msg.h>                                                                                               
    5 #include <string.h>                                                                                                
    6 #include <unistd.h>                                                                                                
    7 struct msgbuf{                                                                                                     
    8   long mtype;                                                                                                      
    9   char mtext[1024];                                                                                                
   10 };                                                                                                                 
   11 int  main()                                                                                                        
   12 {                                                                                                                  
   13   //客户端                                                                                                         
   14   //打开消息队列                                                                                                   
   15   int id = msgget(1234,0);                                                                                         
   16   if(id == -1)                                                                                                     
   17   {                                                                                                                
   18     perror("msgget\n");                                                                                            
   19     exit(1);
   20   }                                                                                                                
   21     struct msgbuf mb;                                                                                              
   22     while(1)                                                                                                       
   23     {                                                                                                              
   24       memset(&mb,0x00,sizeof(mb));                                                                                 
   25       mb.mtype = 1;                                                                                                
   26       *(int *)(mb.mtext) = getpid();                                                                               
   27       //读取键盘                                                                                                   
   28     char *f = fgets(mb.mtext+sizeof(int),1024-sizeof(int),stdin);
            //从标准输入中读到1024-sizeof(int)中              
   29     if(f == NULL)                                                                                                  
   30     {                                                                                                              
   31       break;                                                                                                       
   32     }                                                                                                              
   33       //发送给服务器                                                                                               
   34       msgsnd(id,&mb,strlen(mb.mtext+sizeof(int))+sizeof(int),0);//发送的数据的大小                                 
   35       //读取服务器                                                                                                 
   36       memset(&mb,0x00,sizeof(mb));                                                                                 
   37       msgrcv(id,&mb,1024,getpid(),0);//从进程id的通道中读                                                          
   38       //显示到屏幕                                                                                                  
   39       printf("%s\n",mb.mtext+sizeof(int));                                                                         
   40     }                                                                                                              
   41 } 
    1 #include <stdio.h>                                                                                                 
    2 #include <stdlib.h>                                                                                                
    3 #include <sys/ipc.h>                                                                                               
    4 #include <sys/msg.h>                                                                                               
    5 #include <string.h>                                                                                                
    6 struct msgbuf{                                                                                                     
    7   long mtype;                                                                                                      
    8   char mtext[1024];                                                                                                
    9 };                                                                                                                 
   10 int  main()                                                                                                        
   11 {                                                                                                                  
   12   //服务端                                                                                                         
   13   //创建一个消息队列                                                                                               
   14   int id = msgget(1234,IPC_CREAT| 0644);                                                                           
   15   if(id == -1)                                                                                                     
   16   {                                                                                                                
   17     perror("msgget\n");                                                                                            
   18     exit(1);                                                                                                       
   19   } 
   20   while(1)                                                                                                         
   21   {                                                                                                                
   22     struct msgbuf mb;                                                                                              
   23     memset(&mb,0x00,sizeof(mb));                                                                                   
   24     //创建成功后读取队列号为msgid的通道1中的数据                                                                   
   25   msgrcv(id,&mb,1024,1,0);                                                                                         
   26     //发送给客户端,前四个字节作为通道号发回给客户端                                                                
   27   mb.mtype =*(int *)(mb.mtext);                                                                                    
   28   msgsnd(id,&mb+sizeof(int),strlen(mb.mtext +sizeof(int))+sizeof(int),0);                                          
   29   }                                                                                                                
   30 }     

共享内存:

共享存储映射区中用页表映射到同一个物理内存 实现进程间通信,没有用户态到内核态的相互切换时效率最高的一种进程间通信方式。

shmget(key_t key,size_t size//共享内存段的大小,int flag//创建用IPC_CREAT| 0644);

ipcs中的nattch为链接到共享内存的数量

共享内存和进程建立关系void *shmat(int id,const char *shmaddr,flag);//shmaddr由操作系统自己决定关联到哪个虚拟地址空间NULL,flag为0返回虚拟地址空间的起始位置

int shmdt(void *shmaddr)//参数为起始位置,返回值为失败返回-1

两个关联到共享内存的进程一个读一个写最快的进程间通信方式,没有用户态到内核态间的切换

删除共享内存int shmctl(int shmid, int cmd, struct shmid_ds *buf)//cmd IPC_RMID删除共享内存

删除ipcs -M shmget创建时的文件名(key)

使用共享内存实现一个客户端服务器

 1 #include <unistd.h>                                                                                                  
  2 #include <stdio.h>                                                                                                   
  3 #include <stdlib.h>                                                                                                  
  4 #include <sys/ipc.h>                                                                                                 
  5 #include <sys/shm.h>                                                                                                 
  6 #include <string.h>                                                                                                  
  7 struct stu{                                                                                                          
  8   int id;                                                                                                            
  9   char name[20];                                                                                                     
 10 };                                                                                                                   
 11 int main()                                                                                                           
 12 {                                                                                                                    
 13  int shmid = shmget(1234,sizeof(struct stu),0);                                                                      
 14  if(shmid == -1)                                                                                                     
 15  {                                                                                                                   
 16    perror("shmget\n");                                                                                               
 17  }                                                                                                                   
 18  printf("create succecss\n");                                                                                        
 19 struct stu *p = (struct stu *)shmat(shmid,NULL,0); 
 20 if(p == NULL)                                                                                                        
 21 {                                                                                                                    
 22   perror("shmat");                                                                                                   
 23   exit(1);                                                                                                           
 24 }                                                                                                                    
 25 p->id = 1;                                                                                                           
 26 strcpy(p->name ,"jane");                                                                                             
 27 sleep(30);                                                                                                           
 28 shmdt(p);                                                                                                            
 29 return 0;                                                                                                            
 30 }  
  1 #include <unistd.h>                                                                                                  
  2 #include <stdio.h>                                                                                                   
  3 #include <stdlib.h>                                                                                                  
  4 #include <sys/ipc.h>                                                                                                 
  5 #include <sys/shm.h>                                                                                                 
  6 #include <string.h>                                                                                                  
  7 struct stu{                                                                                                          
  8   int id;                                                                                                            
  9   char name[20];                                                                                                     
 10 };                                                                                                                   
 11 int main()                                                                                                           
 12 {                                                                                                                    
 13  int shmid = shmget(1234,sizeof(struct stu),0);                                                                      
 14  if(shmid == -1)                                                                                                     
 15  {                                                                                                                   
 16    perror("shmget\n");                                                                                               
 17  }                                                                                                                   
 18  printf("create succecss\n");                                                                                        
 19 struct stu *p = (struct stu *)shmat(shmid,NULL,0);  
 20 if(p == NULL)                                                                                                        
 21 {                                                                                                                    
 22   perror("shmat");                                                                                                   
 23   exit(1);                                                                                                           
 24 }                                                                                                                    
 25 printf("p->id = %d,p->name = %s",p->id ,p->name);                                                                    
 26 shmdt(p);                                                                                                            
 27 return 0;                                                                                                            
 28 }

猜你喜欢

转载自blog.csdn.net/jane_yao/article/details/81675437