首页 > 系统相关 >linux进程间通讯

linux进程间通讯

时间:2024-01-24 13:23:54浏览次数:31  
标签:通讯 int shmid include key linux 进程 共享内存 shm


进程间通讯->共享内存

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 */
};

/****************************************************/
#include <sys/ipc.h>
#include <sys/shm.h>
功能:用来创建共享内存
原型
int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段名字,能进行唯一标识,通过ftok()函数获取key值。
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
IPC_CREAT: 如果要创建的共享内存不存在,就创建,如果存在,就获取
IPC_EXCL : 无法单独使用
IPC_CREAT | IPC_EXCL 如果不存在,就创建(一定是一个新的共享内存),如果存在,就出错
返回值:
成功返回一个非负整数,即该共享内存段的标识码;失败返回-1


/****************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
功能:将路径名和项目标识符转换为系统V IPC密钥
原型:
key_t ftok(const char *pathname, int proj_id);

参数
pathname:形成key值的字符串.
proj_id:形成key值的id.

返回值:
失败会返回-1,erron会被设置.


/****************************************************/
#include <sys/types.h>
#include <sys/shm.h>
功能:将共享内存段连接到进程地址空间
原型
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,表示连接操作用来只读共享内存


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

注意:将共享内存段与当前进程脱离不等于删除共享内存段


/****************************************************/
功能:用于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
IPC_STAT: 把shmid_ds结构中的数据设置为共享内存的当前关联值。
IPC_SET : 在进程有足够权限的前提下,把共享内存的当前关联之设置为shimd_ds数据结构中给出的值。
IPC_RMID: 立即删除共享内存段
IPC_INFO:
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:
成功返回0;失败返回-1


/****************************************************/
文件:Makefile
.PHONY:all
all:shm_client shm_server

shm_client:shm_client.cpp
g++ -o $@ $^ -std=c++11
shm_server:shm_server.cpp
g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
rm -f shm_client shm_server

/****************************************************/
文件:comm.hpp
#ifndef _COMM_HPP_
#define _COMM_HPP_

#include <iostream>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define PATHNAME "."
#define PROJ_ID 0X66
// 共享内存的大小,一般建议4kb的整数倍,因为系统分配共享内存是以4kb为单位的!
// 内存划分内存块的基本单位,如果不是,内核会给向上取整!
#define MAX_SIZE 4098

/* 创建key_t值 */
key_t GetKey()
{
  key_t k = ftok(PATHNAME, PROJ_ID);
  if(k < 0)
  {
    std::cerr << errno << ":" << strerror(errno) << std::endl;
    exit(1);
  }
  // 程序走到这里,说明创建key_t值成功.
  return k;
}

/* 创建 | 获取共享内存 */
int GetShmHelper(key_t k, int flags)
{
  // k是要通过shmget()函数,设置进入内存属性中的!用来表示该共享内存,在内核中的唯一性!
  // shmid vs k 类似于 fd vs inode
  int shmid = shmget(k, MAX_SIZE,flags);
  if(k < 0)
  {
    std::cerr << errno << ":" << strerror(errno) << std::endl;
    exit(2);
  }
  return shmid;
}

/* 创建共享内存 */
int CreateShm(key_t k)
{
  return GetShmHelper(k, IPC_CREAT | IPC_EXCL | 0666);
}

/* 获取共享内存 */
int GetShm(key_t k)
{
  return GetShmHelper(k, IPC_CREAT);
}

/* 进程关联共享内存 */
void* AttachShm(int shmid)
{
  void* mem = shmat(shmid, nullptr, 0);
  if((long long)mem == -1L)
  {
    std::cerr << errno << ":" << strerror(errno) << std::endl;
    exit(3);
  }
  return mem;
}

/* 进程去除关联共享内存 */
void DetaShm(void *pStart)
{
  if(shmdt(pStart) == -1)
  {
    std::cerr << errno << ":" << strerror(errno) << std::endl;
  }
}

/* 删除共享内存 */
void DelShm(int shmid)
{
  if(shmctl(shmid, IPC_RMID, nullptr) == -1)
  {
    std::cerr << errno << ":" << strerror(errno) << std::endl;
  }
}

#endif//_COMM_HPP_


/****************************************************/
文件:shm_client.cpp
#include "comm.hpp"
int main()
{
  // 获取共享内存所需要的key值
  key_t k = GetKey();
  printf("0x%x\n", k);
  // 获取共享内存id
  int shmid = GetShm(k);
  printf("shmid: %d\n", shmid);
  sleep(5);

  // 进程关联共享内存
  char* pStart = (char*)AttachShm(shmid);
  printf("Attach success, Address start: %p\n", pStart);
  sleep(5);

  //创建消息内容
  const char* message = "Hello Server,我是另一个进程,正在和您通信";
  int count = 0;
  pid_t id = getpid();

  while(true)
  {
    // 发送信息给server(将消息打印到共享内存)
    snprintf(pStart, MAX_SIZE, "%s[我的pid:%d] [消息编号:%d]", message, id, ++count);
    sleep(1);
  }

  // 去除进程关联共享内存
  DetaShm(pStart);
  sleep(5);

  // 不负责删除server会操作
  return 0;
}

/****************************************************/
文件:shm_server.cpp
// shell脚本监控命令:while :; do ipcs -m; sleep 1; done
#include "comm.hpp"
int main()
{
  // 获取共享内存所需要的key值
  key_t k = GetKey();
  printf("0x%x\n", k);

  // 创建共享内存
  int shmid = CreateShm(k);
  printf("shmid: %d\n", shmid);
  sleep(5);

  // 进程关联共享内存
  char* pStart = (char*)AttachShm(shmid);
  printf("Attach success, Address start: %p\n", pStart);
  sleep(5);

  // 接收client的信息
  while(true)
  {
    //打印共享内存内容
    printf("Client say:%s\n", pStart);

    // 打印共享内存的属性
    struct shmid_ds ds;
    shmctl(shmid, IPC_STAT, &ds); //获取消息属性
    printf("获取属性:size:%d,pid:%d,myself:%d,key:0x%x\n", ds.shm_segsz, ds.shm_cpid, getpid(), ds.shm_perm.__key);

    sleep(1);
  }

  // 去除进程关联共享内存ls
  DetaShm(pStart);
  sleep(10);

  // 删除共享内存
  DelShm(shmid);
  return 0;
}
共享内存优点:
共享内存是所有进程通讯最快的,能大大的减少数据的拷贝次数。
同样的代码分别用管道和共享内存实现,综合考虑管道和共享内存,考虑键盘输入和显示器输出,那么共享内存有几次拷贝?管道几次拷贝?
管道:单纯收发消息4(4+2)
共享内存:单纯收发消息2(2+2)

共享内存缺点:
共享内存是不对数据进行保护的,需要用户自助添加保护功能。

 

 

进程间通讯->消息队列
/****************************************************/
struct msqid_ds
{
  struct ipc_perm msg_perm;   /* Ownership and permissions */
  time_t msg_stime;       /* Time of last msgsnd(2) */
  time_t msg_rtime;       /* Time of last msgrcv(2) */
  time_t msg_ctime;       /* Time of last change */
  unsigned long __msg_cbytes;   /* Current number of bytes in queue (nonstandard) */
  msgqnum_t msg_qnum;      /* Current number of messages in queue */
  msglen_t msg_qbytes;     /* Maximum number of bytes allowed in queue */
  pid_t msg_lspid;        /* PID of last msgsnd(2) */
  pid_t msg_lrpid;        /* PID of last msgrcv(2) */
};

struct ipc_perm
{
  key_t __key;      /* Key supplied to msgget(2) */
  uid_t uid;       /* Effective UID of owner */
  gid_t gid;        /* Effective GID of owner */
  uid_t cuid;        /* Effective UID of creator */
  gid_t cgid;       /* Effective GID of creator */
  unsigned short mode;   /* Permissions */
  unsigned short __seq;    /* Sequence number */
};

/****************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
功能:获取消息队列
原型:
int msgget(key_t key, int msgflg);
返回值:msqid
-1:错误。

/****************************************************/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
功能:设置消息队列
原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:-1:错误


/****************************************************/
The msgp argument is a pointer to a caller-defined structure of the following general form:
struct msgbuf
{
  long mtype;    /* message type, must be > 0 */
  char mtext[1];   /* message data */
};

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
功能:发送消息
原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);


/****************************************************/
#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);


/****************************************************/
// sendmsg.c
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
  long type;
  char text[100];
} message_t;

int main()
{
  key_t key = ftok("/tmp", 'a'); // 创建一个唯一的key
  int msgid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列
  if (msgid == -1)
  {
    perror("msgget");
    exit(EXIT_FAILURE);
  }

  message_t message;
  message.type = 1;
  strcpy(message.text, "Hello, World!");
  int result = msgsnd(msgid, &message, sizeof(message.text), 0);
  if (result == -1)
  {
    perror("msgsnd");
    exit(EXIT_FAILURE);
  }

  printf("消息发送成功,text=%s\n", message.text);

  return 0;
}


/****************************************************/
// rsvmsg.c
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
  long type;
  char text[100];
} message_t;

int main()
{
  key_t key = ftok("/tmp", 'a'); // 创建一个唯一的key
  int msgid = msgget(key, 0666 | IPC_CREAT); // 创建消息队列
  if (msgid == -1)
  {
    perror("msgget");
    exit(EXIT_FAILURE);
  }

  message_t message;
  int result = msgrcv(msgid, &message, sizeof(message.text), 1, 0);
  if (result == -1)
  {
    perror("msgrcv");
    exit(EXIT_FAILURE);
  }

  printf("消息接收成功,text=%s\n", message.text);

  return 0;
}

标签:通讯,int,shmid,include,key,linux,进程,共享内存,shm
From: https://www.cnblogs.com/linux-learn/p/17984464

相关文章

  • Linux7的启动原理和服务控制
    1、CentOS6的启动过程和原理BIOS/UEFI阶段--->GRUB阶段--->内核引导阶段--->Init阶段--->运行级别切换阶段--->服务启动阶段--->图形界面或命令行登录阶段--->用户登录BIOS/UEFI阶段:在计算机开机时,BIOS(或UEFI)会执行自检和硬件初始化,然后从启动设备(通常是硬盘)的MBR(主引导记......
  • Linux计划任务与日志的管理
    1、什么是计划任务我们可以通过一些设置来让电脑定时提醒我们该做什么事了,或者我们提前设置好,告诉电脑你几点做什么几点做什么,这种我们就叫它定时任务。而遇到一些需要执行的事情或任务。我们也可以通过命令来告诉电脑一会临时把这个工作给做一下在我们LINUX中,我们可以通过cront......
  • 进程管理
    一、什么是进程进程是已启动的可执行程序的运行实例,进程有以下组成部分:已分配内存的地址空间安全属性,包括所有权凭据和特权程序代码的一个或多个执行线程进程状态程序:二进制文件,静态/bin/date,/usr/sbin/sshd进程:是程序运行的过程,动态,有生命周期及运行状态......
  • Linux下配置ip地址四种方法
    linux系统安装完,以后通过命令模式配置网卡IP。配置文件通常是/etc/sysconfig/network-scripts/ifcfg-interface-nameifconfig后显示的内容,lo代表loop回路。 一、Ifconfig命令第一种使用ifconfig命令配置网卡的ip地址。此命令通常用来零时的测试用,计算机启动后,ip地址的配置......
  • Linux基本命令
    Linux基本命令pwd查看当前所在的路径完整路径相对路径lsdirll查看目录信息​ ls-a查看当前目录下的信息以及隐藏文件stat查看信息xxx--help查看命令的使用方式创建文件touch命令创建(创建但是不打开)vi/vim(创建一个文件并......
  • VMware虚拟机部署Linux Ubuntu系统的方法
      本文介绍基于VMwareWorkstationPro虚拟机软件,配置LinuxUbuntu操作系统环境的方法。  首先,我们需要进行VMwareWorkstationPro虚拟机软件的下载与安装。需要注意的是,VMwareWorkstationPro软件是一个收费软件,而互联网中有很多可以下载后直接免费激活、使用这一软件的方......
  • Linux系统平均负载3个数字的含义
    文章作者:姜南(Slyar) 文章来源:SlyarHome(www.slyar.com)转载请注明,谢谢合作。越来越多人开始接触Linux操作系统,从VPS到无线路由的刷机系统(如OpenWRT、Tomato),同时也必不可少地会在各式各样的探针和系统监测界面上看到"系统平均负载"或者"LoadAverage"这样的字眼,但是它并不......
  • Linux系统目录和相对路径与绝对路径
    1、系统目录结构Linux只有一个根目录使用tree命令查看linux目录结构[root@fishman-160/]#tree-L1#仅下降一级目录的深度。.├──bin->usr/bin├──boot├──dev├──etc├──home├──lib->usr/lib├──lib64->usr/lib64├──media├─......
  • linux进阶之nmtui和nmcli配置网络
    CentOS7配置网络推荐使用NetworkManager服务(不推荐network服务)。图形化方式:nmtui或Applications->SystemTools->Settings->Network命令方式:->IPv4寻址方式 [X]Automaticallyconnect->默认->自动连接->ONBOOT=yes [X]Availabletoallusers->默认->所有用户均可使用......
  • Qt编写linux系统onvif工具(支持预览/云台/预置位/录像等)
    一、功能特点广播搜索设备,支持IPC和NVR,依次返回。可选择不同的网卡IP进行对应网段设备的搜索。依次获取Onvif地址、Media地址、Profile文件、Rtsp地址。可对指定的Profile获取视频流Rtsp地址,比如主码流地址、子码流地址。可对每个设备设置Onvif用户信息,用于认证获取详细信息......