进程通信(管道、共享内存)

目录

一、匿名管道

1.1创建管道

1.2 父子进程通信

1.3 特点

1.4 情况

二、命名管道

1.命名管道创建

2.通信

三、共享内存

3.1共享内存函数

3.1.1shmget函数

3.1.2shmat函数

3.1.3shmdt函数

3.1.4shmctl函数

3.2通信

3.3共享内存数据结构


一、匿名管道

        管道也是一个文件,用于父子间进程通信。父子间一个打开文件写端,一个打开文件读端,即可通过对管道的读写完成父子间的通信。由于父子间通信的管道没有名字因此称为匿名管道。

1.1创建管道

使用pipefd数组表示管道读写端,并作为参数传给系统调用pipe(),即可完成管道创建,创建失败pipe()返回0。

1.2 父子进程通信

        fork创建进程后,将父进程读端关闭(close(pipefd[0])),子进程写段关闭。这时通过系统调用write和read对管道读写,读写完毕后父子进程关闭读/写端,完成通信。

  1 #include <unistd.h>                                                                                                                   
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4 #include <errno.h>
  5 #include <string.h>
  6 int main()
  7 {
  8   int pipefd[2] = {0};
  9   if(pipe(pipefd)!=0)
 10   {
 11     perror("pipe error\n");
 12   }
 13   pid_t pid = fork();
 14   if (pid == -1)
 15   {
 16     perror("fork error\n");
 17     return 1;
 18   }
 19   if (pid != 0) 
 20   {
 21     close(pipefd[0]);
 22     const char buf[] = "i am father";
 23     write(pipefd[1],buf, strlen(buf));
 24     close(pipefd[1]);
 25   }
 26   close(pipefd[1]);
 27   char buf[20] = {0};
 28   read(pipefd[0], buf, 20);
 29   printf("%s\n", buf);
 30   close(pipefd[0]);
 31   exit(0);
 32   return 0;
 33 }

1.3 特点

①管道是一个单向通信的信道

②管道面向字节流

③匿名管道仅限于父子间通信

④管道自带同步机制,原子性写入

⑤管道的生命周期与进程相同

1.4 情况

①读端和写段中一端执行地慢,另一端都要进行等待

②读端关闭,写端收到SIGPIPE信号直接终止

③写端关闭,读端读完管道内剩余数据,读到最后返回值为0,表示读取结束

二、命名管道

        创建一个命名管道,将两个不相关进程与该管道连接,通过对命名管道读写完成通信。命名管道文件读写不会像一般文件那样去读写磁盘,而是在一个缓冲区进行读写。

1.命名管道创建

//命令行创建
$ mkfifo filename
//调用函数创建
int mkfifo(const char *filename,mode_t mode);
//第一个参数是管道名,第二个是设置权限,成功返回0,失败返回-1

2.通信

        管道创建以后,对管道的读写就直接调用open,write,read等系统调用,对管道像文件一样操作读写即可。一个进程写,一个进程读,即可完成不相关进程的通信。只需要一个进程创建管道,另一个进程访问要通信的进程创建的管道。

1: server.c                                                                                                             
  1 #include <stdio.h>                               
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>                                                        
  5 #include <unistd.h>                                                       
  6 #include <stdlib.h>
  7 
  8 int main()
  9 {
 10   umask(0);
 11   if(mkfifo("./myfifo",0666)<0)
 12   {
 13     perror("mkfifo");
 14     return 1;                                                                                                                         
 15   }
 16   int fd = open("myfifo",O_RDONLY);
 17   if(fd<0)                                                                
 18   {                                                                       
 19     perror("open");   
 20     return 1;
 21   }     
 22   char buf[64];                                                           
 23   ssize_t s = read(fd,buf,sizeof(buf)-1);      
 24   if(s>0)
 25   {   
 26     buf[s] = 0;                                                            
 27     printf("client say:%s",buf);
 28   }
 29   else if(s == 0)
 30   {
 31     printf("client quit\n");
 32   }
 33   else 
 34   {
 35     perror("read");
 36     return 1;
 37   }
 38   close(fd);
 39   return 0;
 40 }              
 2: client.c                                                                                                             
  1 #include <stdio.h>                                                                                                                    
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <unistd.h>
  6 #include <stdlib.h>
  7 #include <string.h>
  8 int main()
  9 {
 10   int fd = open("myfifo",O_WRONLY);
 11   if(fd<0)
 12   {
 13     perror("open");
 14     return 1;
 15   }
 16   char buf[64];
 17   printf("please enter::");
 18   fflush(stdout);
 19   ssize_t s = read(0,buf,sizeof(buf)-1);
 20   if(s<0)
 21   {
 22     perror("read");
 23     return 1;
 24   }
 25   buf[s] = 0;
 26   write(fd,buf,strlen(buf));
 27   close(fd);
 28   return 0;
 29 }

三、共享内存

        共享内存区是最快的进程通信形式。内存映射到共享它的进程的地址空间,进程间数据传递不涉及到内核,即进程不再通过执行进入内核的系统调用来传递彼此的数据。

共享内存属于内核,其生命周期与进程无关。

ipcs -m 查看共享内存

ipcrm -m shmid 删除共享内存

3.1共享内存函数

3.1.1shmget函数

功能:用来创建共享内存
原型 int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段标识符,使用下面的函数得到唯一标识符


size:共享内存大小,建议是4kb的整数倍
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的。ICPC_CREAT表示共享内存存在则返回已存在的共享内存的标识码,否则创建一个新的共享内存。IPC_CREAT | IPC_EXECL,表示必须要一个全新的共享内存空间。
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
功能:将共享内存段连接到进程地址空间

终端输入ipcs -m 可查看共享内存

ipcrm -m (shmid) 删除共享内存

key是系统层用来唯一标识共享内存,在用户层使用shmid来管理共享内存。

3.1.2shmat函数

功能::将共享内存段连接到进程地址空间                                                                                    原型 void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存地址;失败返回-1
shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

3.1.3shmdt函数

功能:将共享内存段与当前进程脱离
原型 int shmdt(const void *shmaddr);
参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

3.1.4shmctl函数

功能:用于控制共享内存
原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)IPC_STAT(设置关联值)、IPC_SET(有权限设置关联值)、IPC_RMID(删除共享内存)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

3.2通信

        共享内存通信用起来更加简单,在有了基本创建、链接、断开链接、删除共享内存的步骤框架后。在链接完毕后,断开链接前直接对共享内存进行读写。以下是一个共享内存通信示例。

1: comm.h                                                                                                             
  1 #pragma once 
  2 #include <stdio.h>
  3 #include <sys/ipc.h>
  4 #include <sys/shm.h>
  5 #define PATH_NAME "./"
  6 #define PROJ_ID 0x6666
  7 #define SIZE 4097
 2: server.c                                                                                                           
  1 #include "comm.h"                                                                                                                     
  2 #include <unistd.h>
  3 int main()
  4 {
  5   key_t key = ftok(PATH_NAME,PROJ_ID);
  6   if(key<0)
  7   {
  8     perror("ftok");
  9     return 1;
 10   }
 11   int shmid = shmget(key,SIZE,IPC_CREAT|IPC_EXCL|0666);
 12   if(shmid<0)
 13   {
 14     perror("shmget");
 15     return 1;
 16   }
 17   char* mem = (char*)shmat(shmid,NULL,0);
 18   if(mem == (void*)-1)
 19   {
 20     perror("shmat");
 21     return 1;
 22   }
 23   while(1)
 24   {
 25     sleep(1);
 26     printf("client say: %s\n",mem);
 27   }
 28 
 29   sleep(1);
 30   shmdt(mem);
 31 
 32   shmctl(shmid,IPC_RMID,NULL);
 33   return 0;
 34 }
3: client.c                                                                                                             
  1 #include "comm.h"
  2 #include <string.h>
  3 
  4 int main()
  5 {
  6   key_t key = ftok(PATH_NAME,PROJ_ID);
  7   if(key<0)
  8   {
  9     perror("ftok");
 10     return 1;
 11   }
 12   int shmid = shmget(key,SIZE,IPC_CREAT);
 13   if(shmid < 0)
 14   {
 15     perror("shmget");
 16     return 1;
 17   }
 18 
 19   char* mem = (char*)shmat(shmid,NULL,0);
 20 
 21   const char* buf = "i am a process A";
 22   strcpy(mem,buf);
 23                                                                                                                                       
 24   shmdt(mem);
 25   return 0;
 26 }

3.3共享内存数据结构

        共享内存由操作系统组织管理。使用信号量来保证同步、互斥。

struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值