weiqi7777

进击吧,linux(十七) 共享内存通讯

0
阅读(1262) 评论(0)

 

Linux进程和进程之间有多种通讯方式。Linux进程间通讯的主要方式有:

1、  无名管道

2、  有名管道

3、  信号

4、  消息队列

5、  共享内存

6、  信号量

7、  套接字

共享内存通讯,从这名字一听就知道这个通讯的方式了。就是利用内存进行通信。两个进程对内存的同一个区域进行数据操作,不就能进行通信了。

通过下面一个图就能清楚的知道共享内存通信。

clip_image002

同样,对共享内存学习也是学习几个函数。

10.1 创建打开共享内存

10.1.1   函数名

      shmget

10.1.2 函数原型

      int shmget(key_t key, size_t size, int shmflg)

10.1.3 函数功能

      创建或者获取共享内存,并返回其描述符id

10.1.4 所属头文件

      <sys/ipc.h>  <sys/shm.h>

10.1.5 函数返回值

      成功: 共享内存的描述符

      失败: -1

10.1.6 参数说明

      key 共享内存的键值

      size 创建的共享内存的大小

      shmflg:打开标志

      -IPC_CREAT: key所关联的共享内存不存在,就创建共享内存

10.2 映射共享内存

10.2.1   函数名

      shmat

10.2.2 函数原型

      void  *shmat(int shmid, const void *shmaddr, int shmflg)

10.2.3 函数功能

      把指定的shmid共享内存映射到进程的地址空间去

10.2.4 所属头文件

      <sys/types.h>  <sys/shm.h>

10.2.5 函数返回值

      成功: 返回映射到进程空间之后的内存地址

      失败: -1

10.2.6 参数说明

      shmid 共享内存的描述符

      shmaddr:指定映射后的内存地址,一般设置为空,即NULL,让系统自动选择映射地址

shmflg:标志,一般设置为0

10.3 分离共享内存

10.3.1   函数名

      shmdt

10.3.2 函数原型

      int shmdt(const void *shmaddr)

10.3.3 函数功能

      从进程地址空间中,断掉与共享内存的联系

10.3.4 所属头文件

      <sys/types.h>  <sys/shm.h>

10.3.5 函数返回值

      成功: 0

      失败: -1

10.3.6 参数说明

      shmaddr 要断开的共享内存的映射地址

10.4 控制共享内存

10.4.1   函数名

      shmctl

10.4.2 函数原型

      int shmctl(int shmid, int cmd, struct shmid_ds *buf)

10.4.3 函数功能

      控制共享内存

10.4.4 所属头文件

      <sys/ipc.h>  <sys/shm.h>

10.4.5 函数返回值

      成功: 根据不同的操作返回不同的值

      失败: -1

10.4.6 参数说明

      shmid:共享内存的描述符

      cmd:   对共享内存的操作命令

      -IPC_STAT: 从指定的共享内存的内核数据中读取数据到buf结构体中

      -IPC_SET: buf结构体中数据写入到指定的共享内存的内核数据中

      -IPC_RMID:删除共享内存

buf: 一个结构体,指向shmid_ds结构体,获取linux中描述共享内存的结构。基本不使用。

clip_image004

           其中的struct ipc_perm也是一个结构体

clip_image005

下面就是写代码来学习以上的函数。

有两个进程AB,进程A创建一个共享内存,然后往这个共享内存中写入数据,进程B获取A创建的共享内存,然后从这共享内存中读取数据。当A进程写入weiqi7777,通信结束,两个进程分离共享内存,最后B进程删除共享内存。

A进程:

#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#define TEXT_SZ 2048
struct memory_share
{
    int flag;
    char text[TEXT_SZ];
};
void main()
{
    key_t key;
    int shmid;
    struct memory_share *p;
    char data[TEXT_SZ];
    /*创建键值*/
    key = ftok("/home",6); 
    /*创建共享内存*/
    shmid = shmget(key,sizeof(struct memory_share),IPC_CREAT);
    if(shmid == -1)
    {
        printf("create shm failed\n");
        exit(EXIT_FAILURE);
    }
    /*映射共享内存*/
    p = (struct memory_share *)shmat(shmid,NULL,0);
   
    /*往共享内存放入数据*/
    while(1)
    {
        while(p->flag == 1);
        fgets(data,TEXT_SZ,stdin);
        strncpy(p->text,data,TEXT_SZ);
        p->flag = 1;       
        if(strncmp(data,"weiqi7777",9) == 0 )
            break;
    }
    /*分离共享内存*/
    shmdt((const void *)p);
}

A进程首先创建键值,因为共享内存是和键值关联的,然后再通过这个键值创建一个共享共存,并将struct memory_share p结构体与共享内存关联。然后就往结构体p中写入数据,不就相当于往共享内存中写入数据了。

最后判断写入的数据是不是weiqi7777,是的话就退出循环,通信结束,然后分离共享内存。

B进程:

#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#define TEXT_SZ 2048
struct memory_share
{
    int flag;
    char text[TEXT_SZ];
};
void main()
{
    key_t key;
    int shmid;
    struct memory_share *p;
    char data[TEXT_SZ];
    /*创建键值*/
    key = ftok("/home",6); 
    /*获取共享内存*/
    shmid = shmget(key,sizeof(struct memory_share),IPC_CREAT);
    if(shmid == -1)
    {
        printf("create shm failed\n");
        exit(EXIT_FAILURE);
    }  
    /*映射共享内存*/
    p = (struct memory_share *)shmat(shmid,NULL,0);
    /*从共享内存里面读取数据,并打印*/
    while(1)
    {
        while(p->flag != 1);
        strncpy(data,p->text,TEXT_SZ);
        p->flag = 0;
        printf("read data: %s",data);  
        if(strncmp(data,"weiqi7777",9) == 0 )
            break;
    }
    /*分离共享内存*/
    shmdt((const void *)p);
    /*删除共享内存*/
    shmctl(shmid,IPC_RMID,NULL);
}

B进程首先也是创建键值,创建的键值和A进程创建的进程要是一样的,然后再通过这个键值获取与A进程创建的共享共存,并将struct memory_share p结构体与共享内存关联。然后就从结构体p中读取数据,不就相当于从共享内存中读取数据了。

最后判断读取的数据是不是weiqi7777,是的话就退出循环,通信结束,然后分离共享内存,最后删除共享内存。

运行程序:

两个进程运行,A进程在等待输入输入,B进程在等待A进程往共享内存中写入数据。

clip_image007

A进程接收键盘输入数据,写入到共享内存中,B进程从共享内存中读取数据,并显示。

clip_image009

当输入的数据是weiqi7777时,两个进程结束,分离共享内存,B进程删除共享内存。

clip_image011

以上就实现了进程间共享内存通信,其实也是比较简单的。