linux基础——IPC进程间通信

简介: linux基础——IPC进程间通信

文章目录

IPC进程间通讯

消息队列

向消息队列发送消息和接收消息

代码示例

共享内存

代码示例

信号量集

代码示例


IPC进程间通讯

使用命令ipcs可以查看IPC的对象。

2020020619540153.png

ftok


#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:转换pathname和proj_id为一个key值
参数:
pathname:指定文件的名字
proj_id:一个整数,这个整数的低8位不能为0
返回值:
成功  key值返回
-1  失败  errno被设置


1.第一步,获取一个键值。

2. 第二步,通过键值获取一块内存,将这块内存的id返回。

3. 第三部,通过内存id来操作这块内存。


代码示例


  • ftok.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
int main(void){
  key_t key;
  //获取键值
  key=ftok("hello",32);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  printf("key=%d\n",key);
  return 0;
}


  • 执行结果

20200206200254625.png

消息队列

通过键值获取一块内存,将这块内存的id返回,需要使用到msgget获取内核内存的id。


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能:获取一个消息队列的id
参数:
key:fotk(3)获取到的键值
msgflg:
IPC_CREAT:
IPC_EXCL:
mode:  指定了消息队列的权限
返回值:
-1  失败   errno被设置
成功返回消息队列的id


代码示例

通过键值获取消息队列的id


  • msgget.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(void){
  key_t key;
  //获取键值
  key=ftok("hello",31);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  printf("key=%x\n",key);
  //通过键值获取消息队列的id
  int msqid=msgget(key,IPC_CREAT|0664);
  if(msqid==-1){
  perror("msgget");
  return 2;
  }
  printf("msgqid=%d\n",msqid);
  return 0;
}


  • 执行结果

20200206200947841.png

向消息队列发送消息和接收消息

msgsnd


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid,const void *msgp,size_t msgsz,\
  int msgflg);
功能:向消息队列发送消息
参数:
msqid:指定了要操作的消息队列的id
msgp:指向struct msgbuf类型的变量的指针
msgsz:是mtext的长度
msgflg:
IPC_NOWAIT   在空间不够的情况下,非阻塞等待,立即返回错误
0     空间不够的情况下,等待空间充足才解除阻塞
返回值:
0  成功
-1  失败  errno被设置


msgrcv


ssize_t msgrcv(int msqid, void *msgp, size_t msgsz,\
   long msgtyp,int msgflg);
功能:从消息队列中获取消息
参数:
msqid:指定了消息队列的id
msgp:指向了获取到的消息
msgsz:是mtext的长度
msgtyp:消息的类型
msgflg:
IPC_NOWAIT:如果消息队列中没有消息,立即返回
0:如果消息队列中没有消息,阻塞等待
返回值:
-1  错误  errno被设置
获取到的消息体的字节数


代码示例

将一个消息放入消息队列中。


  • processA.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct msgbuf{
  long mtype;
  char mtext[256];
}msgbuf_t;
int main(void){
  key_t key;
  msgbuf_t mb;//消息类型的变量
  //获取key值
  key=ftok("hello",31);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  //获取消息队列的id
  int msqid=msgget(key,IPC_CREAT|0664);
  if(msqid==-1){
  perror("msgget");
  return 2;
  }
  //初始化消息
  mb.mtype=3;/*must be >0*/
  strcpy(mb.mtext,"this is test\n");
  //向消息队列中写入消息
  int s=msgsnd(msqid,&mb,strlen(mb.mtext)+1,0);
  if(s==-1){
  perror("msgsnd");
  return 3;
  }
  return 0;
}


从消息队列中获取消息并显示


  • processB.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
typedef struct msgbuf{
  long mtype;
  char mtext[256];
}msgbuf_t;
int main(void){
  key_t key;
  msgbuf_t mb;//消息类型的变量
  //获取key值
  key=ftok("hello",31);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  //获取消息队列的id
  int msqid=msgget(key,IPC_CREAT|0664);
  if(msqid==-1){
  perror("msgget");
  return 2;
  }
  //从消息队列中获取消息
  int s=msgrcv(msqid,&mb,256,3,0);
  if(s==-1){
  perror("msgrcv");
  return 3;
  }
  printf("%s",mb.mtext);
  return 0;
}


  • 执行结果

20200206202123367.png

共享内存

根据键值获取共享内存的id,通过shmget获取共享内存id。

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

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:
参数:
key:ftok(3)返回的键值
size:指定了共享内存的尺寸
shmflg:
IPC_CREAT:指定创建共享内存段
IPC_EXCL:
mode:
返回值:
-1  错误
返回共享内存段的id


将共享内存映射到进程的虚拟地址空间中,使用shmat

shmat(2)


#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:将共享内存绑定到进程的地址空间里
参数:
shmid:共享内存的id
shmaddr:指定了进程绑定共享内存的地址。指定为NULL,有系统做选择
shmflg:
SHM_RDONLY:共享内存段只读
返回值:
返回和共享内存段绑定的地址
 (void *) -1  错误  errno被设置


*int shmdt(const void shmaddr);


功能:解除和共享内存段的绑定
参数:
shmaddr:指定了要解除的共享内存段在进程中的地址
返回值:
0  成功
-1  失败 errno被设置


代码示例

创建共享内存段。


  • shm.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main(void){
  key_t key;
  //获取键值
  key=ftok("hello",41);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  printf("key:%d\n",key);
  //根据键值获取shmid
  int shmid=shmget(key,1024,\
    IPC_CREAT|0664);
  if(shmid==-1){
  perror("shmget");
  return 2;
  }
  printf("获取到共享内存%d\n",shmid);
  return 0;
}


  • 执行结果

20200206203046194.png

使用共享内存完成进程间通信:


  • shmA.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(void){
  key_t key;
  //获取键值
  key=ftok("hello",41);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  printf("key:%d\n",key);
  //根据键值获取shmid
  int shmid=shmget(key,1024,\
    IPC_CREAT|0664);
  if(shmid==-1){
  perror("shmget");
  return 2;
  }
  printf("获取到共享内存%d\n",shmid);
  //将共享内存映射到进程的虚拟地址空间
  void *p=shmat(shmid,NULL,0);
  if(p==(void *) -1){
  perror("shmat");
  return 3;
  }
  //拷贝字符串到共享内存段
  strcpy(p,"hello tarena\n");
  //解除绑定
  shmdt(p);
  return 0;
}


  • shmB.c
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
int main(void){
  key_t key;
  //获取键值
  key=ftok("hello",41);
  if(key==-1){
  perror("ftok");
  return 1;
  }
  printf("key:%d\n",key);
  //根据键值获取shmid
  int shmid=shmget(key,1024,\
    IPC_CREAT|0664);
  if(shmid==-1){
  perror("shmget");
  return 2;
  }
  printf("获取到共享内存%d\n",shmid);
  //将共享内存映射到进程的虚拟地址空间
  void *p=shmat(shmid,NULL,0);
  if(p==(void *) -1){
  perror("shmat");
  return 3;
  }
  //将共享内存段的内容输出到显示器
  printf("%s",(char *)p);
  //解除绑定
  shmdt(p);
  return 0;
}


  • 执行结果


信号量集

具体参考代码示例


代码示例

  • mycp.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void copy_file(int s,int d){
  int r,w;
  char buf[1024];
  char *tmp;
  r=read(s,buf,1024);
  while(r>0){
  tmp=buf;
  while(1){//将读出的内容完全写入到目标文件
    w=write(d,tmp,r);
    r=r-w;
    tmp+=w;
    if(r==0)break;
  }
  r=read(s,buf,1024);
  }
  return; 
}
int main(int argc,char *argv[]){
  int s_fd,d_fd;
  //以只读方式打开源文件
  s_fd=open(argv[1],O_RDONLY);
  if(s_fd==-1){
  perror("open s");
  return 1;
  }
  //以写的方式打开目标文件
  d_fd=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
  if(d_fd==-1){
  perror("open d");
  return 2;
  }
  copy_file(s_fd,d_fd);
  close(s_fd);
  close(d_fd);
  return 0;
}


  • 执行结果

20200206204426696.png

相关文章
|
8月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
308 67
|
7月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
224 16
|
7月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
144 20
|
6月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
131 0
|
6月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
203 0
|
6月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
133 0
|
6月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
185 0
|
9月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
353 4
|
9月前
|
Linux Shell
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
714 5
|
9月前
|
Linux 应用服务中间件 nginx
Linux 进程管理基础
Linux 进程是操作系统中运行程序的实例,彼此隔离以确保安全性和稳定性。常用命令查看和管理进程:`ps` 显示当前终端会话相关进程;`ps aux` 和 `ps -ef` 显示所有进程信息;`ps -u username` 查看特定用户进程;`ps -e | grep &lt;进程名&gt;` 查找特定进程;`ps -p &lt;PID&gt;` 查看指定 PID 的进程详情。终止进程可用 `kill &lt;PID&gt;` 或 `pkill &lt;进程名&gt;`,强制终止加 `-9` 选项。
148 3