进程间的通信机制

IPC,进程间通信
1)文件
2)信号
3)管道
4)共享内存
5)消息队列
6)信号量
7)socket
1 管道
1.1 有名管道
1)命令行方式
mkfifo fifo
2)编程模型
A进程                   B进程                 相关函数
-----------------------------------------------------------------
 创建管道                                         mkfifo()
-----------------------------------------------------------------
写打开管道               读打开文件               open()
-----------------------------------------------------------------
写入数据                 读出数据                 write/read
-----------------------------------------------------------------
关闭管道                  关闭管道                close
-----------------------------------------------------------------
删除管道                                           unlink
----------------------------------------------------------------
1.2 无名管道(适用于父子进程之间的通信)
涉及到的API函数,pipe()
#include <unistd.h>
int pipe(int pipefd[2])
作用:创建管道文件
 以只读方式打开管道文件,将文件描述符保存到pipefd[0]
 以只写方式打开管道文件安,将文件描述符保存到pipefd[1]
编程步骤:
1)调用pipe函数,在内核中创建管道文件,并通过输出参数pipefd[0]获得读或者写管道的文件描述符
2)调用fork函数,创建子进程
3)写数据的进程,关闭读端,close(pipefd[0])
4)度数据的进程,关闭写端,close(pipefd1[1])
5)父子进程分别关闭自己的文件描述符
编程:一端写入20个数据,另一端读出这20个数据
pipe.c
1.3 管道特点
通常使用的管道都是半双工的
2 共享内存 消息队列 信号量集
以上三种IPC被称作 XSI IPC,编程具有很大的共性
1)标识符(身份) 和键(身份证编号)
2)键值如何确定?(身份证的编码方式)
a)使用宏IPC_PRIVATE作为KEY:一般用于父子进程之间
b)可以使用ftok()函数来创建key(重点)
c)在公共头文件中定义每个使用的key给一个固定值
  key本质上就是一个整数
3)服务器进程用此键值来创建IPC对象
xxxget():shmget() /msgget()/ semget()
  客户机进程用此键值来获取该IPC对像
4)服务器进程和客户机进程之间就可以交换信息了
  系统提供的函数:
共享内存:shmat()
消息队列:msgsnd() msgrecv()
信号量集:semop()
5)获取IPC对象的属性信息
xxxctl:shmctl()/ msgctl()/ semctl()
6)销毁创建的IPC对象
xxxctl:shmctl()/ msgctl()/ semctl()
3 共享内存
内核管理一篇物理内存,允许不同进程映射,多个进程可以映射同一块物理内存,映射后的
虚拟地址可能不尽相同,但对应的物理地址相同。
映射物理内存叫挂接,使用后接触映射叫脱节
3.1编程步骤
1)获得key,头文件中定义或者使用:ftok()
#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(const char *pathname, int proj_id)
psthname:存在并且可访问的路径(文件名)
proj_id:取值范围为1-255
2)使用key来创建或者获取一块共享内存:shmget()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)
key:就是ftok()返回值
size:
要申请的共享内存的字节数
建议size为4096的整数倍
若是创建共享内存,必须指定size为非0
若是获取共享内存,size取0即可
shmflg:
IPC_CREAT:创建共享内存
IPC_EXCL:测试key对应
modes:
3)映射共享内存,挂接:shmat()
#include<sys/types.h>
#include<sys/shm.h>
void *shmat(int shmid, const void *shmadd, int shmflg)
shmid:要映射的共享内存段
shmaddr:等价于mmap()函数中的addr,通常区0,由操作系统分配即可
shmflg:
0:以读写方式使用共享内存
SHM_RDONLY:以只读方式使用共享内存
返回值:成功返回虚拟地址的首地址
   出错返回-1
4)使用共享内存进行数据交换(C编程)

5)解除映射,脱接:shmdt()
#include<sys/types.h>
#include<sys/shm.h>
int shmdt(sonst void *shmaddr)
返回值:成功0
失败-1
6)如果后续不会再使用该共享内存,销毁该共享内存:shmctl()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
shmid:
cmd:
IPC_RMID:销毁共享内存
buf:
返回值:成功0
失败-1
errno
3.2 编程
shma.c 
shmb.c

编程获取属性字段:
shmctl.c
struct shmid_ds:
练习:shma进程如果没有按下回车,而是ctrl+c,会造成他所创将的共享内存得不到销毁,
     如何树立该问题?
 处理消息响应函数。

3.3 命令行访问IPC
ipcs:查看系统中现有的共享内存,消息队列,信号量集
     -a:查看所有
 -m:查看共享内存
 -q:查看消息队列
 -s:信号量集
ipcrm:删除IPC
 -q
 -m
 -s
 -M
 -Q
重启:也可以销毁文件

3.4 特点
优点:最快的IPC。

缺点:需要自己编程解决访问共享内存的同步问题

4 消息队列
先把要传递的数据封装到消息中,然后把消息存入队列
消息队列也是采用内存做交互的媒介,系统内核管理一个队列,完成消息的FIFO
4.1 编程步骤
1)创建key
2)使用msgget()来创建/获取消息队列
3)向队列中存入消息msgsnd,取出消息msgrcv()
  int msgsnd(msgid,msgp,size,msgflg)
  msgid,确定操作那个操作队列
  msgp,写入消息队列的数据
  size,消息长度
  msgflg,0 代表阻塞,写入不成功不反回
  IPC_NOWAIT 非阻塞,写入不成功,立即返回错误信息
  int msgrcv(msgid, msgp, size, msgtype, msgflg)
  msgid:确定要操作那个消息队列
  msgp:取到消息放入的缓冲区
  size:期望获得消息长度
  msgtype:0 取消消息队列中的第一消息,忽略类型
          >0 接受特定类型消息中的第一个
  <0 接受类型小于等于msgtype绝对值的消息,
  msgflg:0代表阻塞,读取不成工不返回
  IPC_NOWAIT,非阻塞,不成功立即返回一个错误信息
  返回值:成功返回读取到的字节个数
  失败返回
4)销毁消息队列msgctl
4.2 正规用法
消息分有类型消息和无类型消息。有类型消息编程规范,接收数据时可以进行细分。
涉及到的消息结构体
struct msgbuf

long mtype;//消息类型
buf;//缓冲区

5 信号量集
1)一般用于进程间通信
2)信号量的集合(数组)
3)信号量和信号没有任何关系
4)信号量本质是一个计数器(int),负责控制访问共享资源的最大并行进程总数。信号量
5)初始设为最大值。每个进程访问共享资源前计数减一,每个进程结束共享资源访问计数加一。
  当计数减为0时阻塞,知道计数重新大于0,解除阻塞。
6)如果有多个共享资源需要分别控制最大并行进程数,就需要多个信号量。把多个信号量放在
  一个数组中,这个数组就叫信号量集。
7)编程时,系统提供的接口操作对象是信号量集,而不是单一的信号量。
5.1 编程步骤
1)生成key ftok()
2)创建信号量集 semget()
  int semget(key,nsems, flag)
key:获取/创建信号量集的唯一标志
nsems:信号量的个数
flag:IPC_CREAT:
 IPE_EXCL:
 mode:权限属性
返回值:错误返回-1
   成功返回信号量集合的ID
3)设置初始值 semctl()
int semctl(semid, semnum, cmd, ...)
semid:要操作那个信号量
semnum:要操作第几个信号量
cmd:IPC_RMID:删除信号量集合
SETVAL:设置semid信号量集中第semnum个信号量的值为arg.val
union semum
{
int val;
...
}
IPC_STAT:
IPC_SET:
aggument:

4)正常使用,访问共享资源信号量-1
  访问结束信号量+1
  semop
5)销毁信号量集合
  semctl(, IPC_RMID,...)
  
  sema.c
  semb.c
  int semop(int semid, struct sembuf *sops, unsigned nsops)
  semid
  sops:
      struct sembuf
  {
sem_num:信号量的下标
sem_op:操作数
sem_flg:操作的标记
}
   该函数对semid指定的信号量集合中,由sops所指向的包含nsops个元素的,依次执行如下操作:
sem_op>0:将sem_op加到sem_num对应的信号量的计数值上去
sem_op<0:将sem_op加到sem_num对应的信号量的计数值上去
sem_op=0:将sem_num对应的信号量计数为0才返回
sem_flg:0:代表阻塞
1:IPC_NOWAIT,非阻塞,不等待,出错返回
nsops:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值