LINUX之IPC

LINUX中的IPC

用于多个进程间进行通讯的手段

多个进程间通讯的手段有三种(IPC)

共享内存

信号量

消息队列

IPC通信的唯一性

我们现在所使用的操作系统,多用户多任务的操作系统

多个任务间的通讯可能会用到多个的 IPC

在操作系统上可能会同时存在多个 IPC

在使用 IPC 进行通讯的时候 就需要找到合适的那个 IPC

要想能够找到最合适的那个 IPC 就需要有一个唯一识别 IPC 的东西

这个能够唯一识别 IPC 的东西 就叫做键值

可以类比成进程号

键值的创建

函数的头文件

#include <sys/types.h>
#include <sys/ipc.h>

原函数

key_t ftok(const char *pathname, int proj_id);

函数的参数

const char *pathname 参考文件 建议写绝对路径

int proj_id 参考 id 0-255

函数的返回值

成功返回 键值

失败返回 -1

PS:ftok 的两个参数只要一样 在任意的文件夹下执行 ftok 的函数

得到的键值都是一样的

共享内存

共享内存就是一块共享的内存,共享内存是全局变量的一个加强版

全局变量的特性

作用域

整个工程

生命周期

随着工程的结束而结束

共享内存的特性

作用域

整个操作系统

生命周期

跟随操作系统

查看共享内存
ipcs -m

进程启动的时候要做的事情

进程在启动的时候会做两件事

1) 打开三个标准的文件描述符

0 标准输入

1 标准输出

2 标准错误

2) 操作系统会虚拟出一块 4G 大小的内存空间

0-3G 用户空间

3-4G 内核空间

虚拟出的这块空间进程是可以直接的使用的

共享内存的创建

函数头文件

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

函数原型

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

函数的参数

key_t key, 键值

size_t size, 要创建的共享内存的大小

int shmflg IPC_CREAT|0644 如果共享内存不存在则创建,并赋予 0644 的权限,如果共享内存存在则打开共享内存

函数的返回值

成功返回 共享内存的 id

失败返回 -1

PS:

通过 shmget 这个函数创建的共享内存位于操作系统的内存空间上的

但是操作系统的内存空间不允许我们直接的访问

进程虚拟出来的内存空间 进程是可以直接访问的

假如虚拟出来的内存空间跟创建的内存空间有一定的关系

就可以间接的访问到共享内存

这个建立关系的过程就叫做内存的映射

内存的映射需要借助于系统提供的函数

共享内存的映射

函数的头文件

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

函数的原型

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

函数的参数

int shmid, 共享内存的 id

const void *shmaddr, 要将共享内存映射的位置虚拟的内存空间的位置NULL 表示由系统自动分配一块可用的空间

int shmflg 0 一般为0

函数的返回值

成功返回 映射后的地址

失败返回 NULL

解除映射

函数的头文件

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

函数的原型

int shmdt(const void *shmaddr);

函数的参数

const void *shmaddr:映射后的地址

函数的返回值

成功返回 0

失败返回 -1

删除共享内存

函数的头文件

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

函数的原型

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

函数的参数

int shmid, 共享内存的 id

int cmd, 要执行的动作, IPC_RMID 删除共享内存

struct shmid_ds *buf NULL

函数的返回值

成功返回 0

失败返回 -1

PS:这个函数是一个多功能复用的一个函数

实例

写空间

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
key_t k;
int shmid;
char *p=NULL;
int main()
{
     k = ftok("/",5);//创建键值
     printf("k=%x\n",k);
     shmid = shmget(k,10,IPC_CREAT|0644);//创建共享内存
    if(shmid < 0)
    {
        perror("shmget");
        return -1;
    }
    p = shmat(shmid,NULL,0);//内存的映射
    if(p == NULL)
    {
        perror("shmat");
        return -1;
    }
    //向内存写入数据
    strcpy(p,"LQHAIXX\n");
    //解除映射
    shmdt(p);
    return 0;
}

读空间

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>

key_t k;
int shmid;
char *p=NULL;

int main()
{
    //创建键值
    k= ftok("/",5);
    //打开共享内存
    shmid = shmget(k,10,IPC_CREAT|0644);
    //内存映射
    p=shmat(shmid,NULL,0);
    //读取数据
    printf("p=%s\n",p);
    //删除共享内存
     shmctl(shmid,IPC_RMID,NULL);
    return 0;
}

信号量

信号量的本质就是一个数字

这个数字代表临界资源的数目

这个数字可以进行加也可以进行减

当这个数字加的时候表示 进程在释放资源

当这个数字减的时候 表示有进程在消耗资源

当这个数字减到 0 的时候 表示资源消耗完毕

如果还有进程来申请资源 进程就会阻塞

信号量的主要的作用保护临界资源

查看信号量相关的指令

ipcs -s

创建/打开信号量

函数的头文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

函数的原型

int semget(key_t key, int nsems, int semflg);

函数的参数

key_t key, 键值

int nsems, 信号量的个数 一般写 1

int semflg IPC_CREAT|0644

函数的返回值

成功返回 信号量的 id

失败返回 -1

设置信号量的值/删除信号量

函数的头文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

函数的原型

int semctl(int semid, int semnum, int cmd, ...);

函数的参数

int semid, 信号量的 id

int semnum, 信号量数组下标

int cmd, SETVAL 设置信号量的值

第四个参数直接写要给的值 IPC_RMID 删除信号量

函数的返回值

成功返回 0

失败返回 -1

信号量的消耗/释放

函数的头文件

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>

函数的原型

int semop(int semid, struct sembuf *sops, size_t nsops);

函数的参数

int semid, 信号量的 id

struct sembuf *sops, 执行的操作结构体

size_t nsops 要操作的信号量的个数

函数的返回值

成功返回 0

失败返回 -1

执行的操作结构体

struct sembuf{
unsigned short sem_num; 数组下标
short sem_op; +1 释放信号量
              -1 消耗信号量
short sem_flg; 0 阻塞的消耗信号量
}

实例

sing1运行完才会运行sing2

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int i=0;
key_t k;
int semid;
struct sembuf mysem;
int main()
{
    //创建键值
    k=ftok("/",5);
    
    //创建信号量
    semid = semget(k,1,IPC_CREAT|0644);
    //设置信号量的值
    semctl(semid,0,SETVAL,1);
    //消耗信号量
    
    mysem.sem_num = 0;
    mysem.sem_op =-1;
    mysem.sem_flg = 0;
    semop(semid,&mysem,1);
        for(i=0;i<10;i++)
        {
            printf("i=%d\n",i);
            sleep(1);
        }
        mysem.sem_op =1;
        semop(semid,&mysem,1);
        
    return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int i=0;
key_t k;
int semid;
struct sembuf mysem;
int main()
{
    
    
    //创建键值
    k=ftok("/",5);
    
    //创建信号量
    semid = semget(k,1,IPC_CREAT|0644);
    //消耗信号量
    mysem.sem_num = 0;
    mysem.sem_op =-1;
    mysem.sem_flg = 0;
    semop(semid,&mysem,1);
    
        for(i=0;i<10;i++)
        {
        printf("i=%d\n",i);
        sleep(1);
        }
        mysem.sem_op =1;
        semop(semid,&mysem,1);
    return 0;
}

消息队列

消息队列相关基础知识

消息队列就是用来存放消息的队列

具有先进先出的特性

消息队列里的消息是可以进行分类

消息队列里的消息读取完成之后就消失了

创建消息队列

函数的头文件

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

函数的原型

int msgget(key_t key, int msgflg);

函数的参数

key_t key, 键值

int msgflg IPC_CREAT|0644

函数的返回值

成功返回 消息队列的 id

失败返回 -1

往消息队列里发送消息

函数的头文件

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

函数的原型

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

函数的参数

int msqid, 消息队列的 id

const void *msgp, 消息的结构体

size_t msgsz, 消息的大小 不包含类型

int msgflg 0 阻塞的发

函数的返回值

成功返回 0

失败返回 -1

消息结构体

struct msgbuf {
           long mtype;
           char mtext[80];
       };

从消息队列里读取消息

函数的头文件

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

函数的原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

函数的参数

int msqid, 消息队列的 ID

void *msgp, 读取到的消息存放的位置

size_t msgsz, 消息的大小

long msgtyp, 消息的类型

int msgflg 0 阻塞的收

函数的返回值

成功返回 成功读取的字节数

失败返回 -1

消息队列的删除

函数的头文件

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>

函数的原型

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

函数的参数

int msqid, 消息队列的 id

int cmd, 要执行的动作 IPC_RMID

struct msqid_ds *buf NULL

函数的返回值

成功返回 0

失败返回 -1

实例

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
key_t k;
int msgid;
struct msgbuf {
           long mtype;
           char name[10];
           char passwd[10];
       }mybuf;

int main()
{
    
    //创建键值
    k=ftok("/",5);
    
    //创建消息队列
    msgid = msgget(k, IPC_CREAT|0644);
    //发送消息
    mybuf.mtype = 1;
    strcpy(mybuf.name,"LQHXXX");
    strcpy(mybuf.passwd,"521125");
    
    msgsnd(msgid,&mybuf,sizeof(mybuf)-sizeof(long),0);
    return 0;
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
key_t k;
int msgid;
struct msgbuf {
           long mtype;
           char name[10];
           char passwd[10];
       }mybuf;

int main()
{
    
    //创建键值
    k=ftok("/",5);
    
    //创建消息队列
    msgid = msgget(k,IPC_CREAT|0644);
    //从消息队列读取数据
    msgrcv(msgid,&mybuf,sizeof(mybuf),1,0);
    printf("name=%s,passwd=%s\n",mybuf.name,mybuf.passwd);
    //删除消息队列
    msgctl(msgid,IPC_RMID,NULL);
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值