UNIX_C 高级编程<五>
来源:互联网 发布:上海淘宝代理运营 编辑:程序博客网 时间:2024/05/01 23:46
进程间的通信技术
进程间的通信就是指不同进程之间的信息交互/交换;
a.文件
b.信号
c.管道
d.共享内存
e.消息队列
f.信号量集
g.网络
其中,d、e、f 三种通信方式统称为XSI IPC通信方式
使用管道实现进程间的通信
管道本质上就是文件,只是该文件比较特殊,叫做管道文件
管道主要分为两大类:
有名管道:主要用于任意两个进程间的通信
无名管道:主要用于父子间进程的通信
有名管道实现进程间的通信
mkfifo a.pipe —— 终端下创建管道文件
echo hello > a.pipe —— 表示写入字符串hello到文件a.pipe,写入阻塞
另起一终端,使用命令cat a.pipe读取管道文件内容,此时可以看到hello,写入端阻塞解除
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参 1:路径名
参 2:权限
功能:创建有名管道文件
使用无名管道实现进程间通信
#include <unistd.h>
int pipe(int pipefd[2]);
功能:主要用于创建单向的数据通道实现进程间的通信,通过参数返回两个文件描述符,
其中pipefd[0]关联管道的读端,pipefd[1]关联管道的写端
注意:管道的特殊性就是在于仅仅作为进程间通信的媒介,而本身并不会存储任何的数据;
管道是一中半双工的通信方式,也就是古老的通信方式
使用共享内存实现进程间的通信
共享内存本质上就是由系统内核维护的一块内存区域,该内存区域可以被映射到两个不同进程的虚拟地址空间中,这两个进程通过都写该内存空间从而实现通信;
共享内存是最快的通信方式;
通信模型
1、获取key值,使用ftok函数
2、创建/获取共享内存,使用shmget函数
3、挂接共享内存,使用shmat函数
4、访问共享内存
5、脱节共享内存,使用shmdt函数
6、如果不再使用, 则删除共享内存, shmctl函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
key_t key = ftok(const char*pathname, int proj_id);
参 1:字符串形式的路径名,必须关联一个存在的,并且可以访问的文件
参 2:项目的编号,必须是非零低八位二进制位
返回:成功返回生成key值,失败 —— -1
功能:主要用于根据参数指定的路径和项目编号来生成key值
注意:使用相同的路径名和相同的项目编号,生成的key值也相同
int shmid = shmget(key_t key, size_t size,int shmflg);
参 1:key值,ftok函数的返回值
参 2:共享内存的大小
0 - 获取已经存在的共享内存
参 3:具体的操作标志 ( IPC_CREAT | IPC_EXCL | 0664 )
IPE_CREAT —— 不存在则创建,存在则打开
IPE_EXCL —— 与IPC_CREAT搭配使用,存在则创建失败
0 —— 获取已经存在的共享内存
返回:成功返回共享内存ID,失败返回-1
功能:主要用于创建/获取共享内存
void * pv = shmat(int shmid, const void *shmaddr, int shmflg);
参 1:共享内存的ID, shmget函数的返回值
参 2:共享内存的地址,用系统选择地址给NULL
参 3:共享内存的操作标志,默认给0
返回:成功返回挂接地址,失败返回if( (void *)-1 == pv )
功能:主要用于将参数shmid指向的共享内存段挂接到当前正在调用进程的地址空间中
int shmdt(const void *shmaddr);
功能:主要用于脱接参数指定的共享内存从当前的地址空间中,参数一般传shmat函数返回值
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参 1:共享内存的ID, shmaget函数的返回值
参 2:具体的操作命令 IPC_RMID
参 3:结构体指针类型 NULL
功能:主要用于对指针的共享内存执行指定的操作;
常用的基本命令
ipcs -m 表示察看系统中已经存在的共享内存
ipcrm -m 内存id号 共享内存的ID表示删除指定的共享内存
1 //使用共享内存使用进程间的通信 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <sys/types.h> 6 #include <sys/ipc.h> 7 #include <sys/shm.h> 8 #include <signal.h> 9 10 //定义全局变了定义共享内存的ID11 int shmid;12 13 void fa(int singnum)14 {15 printf("正在删除共享内存,请稍后..\n");16 17 sleep(3);18 19 //调用shmctl函数实现删除操作20 21 int res = shmctl(shmid, IPC_RMID, NULL);22 if(-1 == res )23 {24 perror("shmctl");25 exit(-1);26 }27 28 printf("删除共享内存成功\n");29 30 exit(0); //终止进程31 32 }33 34 int main(void)35 {36 37 //1.获取key值,使用ftok函数38 39 key_t key = ftok(".", 100);40 if (-1 == key )41 {42 perror("key error");43 exit(-1);44 }45 46 printf("key = %#x\n", key);47 48 //2.创建共享内存,使用shmget函数49 50 shmid = shmget(key, sizeof(int), IPC_CREAT | IPC_EXCL | 0664);51 if( -1 == shmid )52 {53 perror("SHMGET ERROR");54 exit(-1);55 }56 57 printf("shmid = %d\n", shmid);58 59 //3.挂接共享内存,使用shmat函数60 void* pv = shmat(shmid, NULL, 0);61 if( (void *) -1== pv)62 {63 perror("shmat");64 exit(-1);65 }66 67 printf("挂接共享内存成功\n");68 //4.访问共享内存,存放数据10069 70 *(int *)pv = 100;71 72 //5脱接共享内存,使用shmdt函数73 74 int res = shmdt( pv );75 if(-1 == res )76 {77 perror("shmdt");78 exit(-1);79 }80 81 printf("脱接共享内存成功\n");82 //6.如果不再使用,删除共享内存,shmctl83 84 printf("删除共享内存按,ctrl+c...\n");85 86 if( SIG_ERR == signal(SIGINT, fa) )87 {88 perror("signal");89 exit(-1);90 }91 92 while(1);93 94 return 0;95 }
使用消息队列实现进程间的通信( 重点 )
首先将传递的数据打包成消息,其中一个进程负责将消息发送到消息队列中,另外一个进程负责接受消息队列中的消息,从而实现通信
通信模型
1、获取key值,使用ftok函数
2、创建/获取消息队列,使用msgget函数
3、发送/接收消息,使用msgsnd/msgrcv函数
4、如果不再使用,则删除消息队列,使用msgctl函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
key_t key = ftok(const char *pathname, int proj_id);
参 1:字符串形式的路径名,必须关联一个存在的,并且可以访问的文件
参 2:项目的编号,必须是非零低八位二进制位
返回:成功返回生成key值,失败 —— -1
功能:主要用于根据参数指定的路径和项目编号来生成key值
注意:使用相同的路径名和相同的项目编号,生成的key值也相同
int msqid = msgget(key_t key, int msgflg);
参 1:key值,ftok的函数返回值
参 2:具体的操作标志 ( IPC_CREAT | IPC_EXCL | 0664 )
IPE_CREAT —— 不存在则创建,存在则打开
IPE_EXCL —— 与IPC_CREAT搭配使用,存在则创建失败
0 —— 获取已经存在的消息队列
返回:成功返回消息队列的ID,失败返回-1
功能:主要用于创建/获取消息队列,从而获得ID
(发送) int msgsnd(int msqid, const void *msgp,size_t msgsz, int msgflg);
参 1:消息队列的ID,msgget函数的返回值
参 2:消息的首地址
struct msgbuf {
long mtype; /* 消息的类型,必须 > 0*/
char mtext[1]; /* 消息的数据内容 可以是其它类型 */
};
参 3:用于指定消息内存的大小也就是(char mtext[1])的大小,不包括long mtype
参 4:发送消息的标志 默认0 —— 阻塞状态
功能:主要用于指定消息队列中发送指定消息
(接收) ssize_t msgrcv(int msqid, void *msgp,size_t msgsz, long msgtyp, int msgflg);
参 1:消息队列的ID,msgget函数的返回值
参 2:消息的首地址
struct msgbuf {
long mtype; /* 消息的类型,必须 > 0*/
char mtext[1]; /* 消息的数据内容 可以是其它类型 */
};
参 3:用于指定消息内存的大小也就是(char mtext[1])的大小,不包括long mtype
参 4:消息的类型
0 —— 表示读取消息队列中第一个消息
>0 —— 表示读取消息队列中第一个类型为msgtyp的消息
<0 —— 表示读取消息队列中第一个类型<=msgtypede的绝对值的消息,其中最小的类型优先读取
参 5:发送消息的标志 默认0 —— 阻塞状态
返回:成功返回实际接收数据的大小,失败返回-1
功能:主要用于指定消息队列中接收指定消息
2 1 3 1 2 3 2
-------------------------------
<-- a b c d e f g <----
-------------------------------
当读取的消息类型是0时: a b c e f g
当读取的消息类型是2时: a c g
当读取的消息类型是-2时:b d a c g
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参 1:消息队列的ID,msgget函数返回值
参 2:具体的操作命令IPC_RMID 删除消息队列,此时第三个参数给NULL
参 3:结构体指针
功能:主要用于操作指定消息队列中的消息
常用的基本命令
ipcs -q 察看当前系统已经存在的消息队列
ipcsrm -q 消息队列的ID 表示删除指定的消息队列
使用信号量集实现进程间的通信
信号量本质就是一种计数器,用于控制同时访问同一种共享资源的进程/线程的个数
信号量的工作原理
a、初始化信号量到最大值
b、如果有进程申请到了一个资源,则信号量减一
c、当信号量的数值为0时,让申请资源的进程进入阻塞状态
d、如果有进程释放了一个资源,则信号量加一
e、只要信号量的数值>0,则阻塞的进程就可以继续抢占资源,抢占不到的进程继续阻塞
什么是信号量集
信号量集本质上就是信号量的集合,用于控制多种共享资源被同时访问的进程/线程个数
通信模型
a、获取key值,使用ftok函数
b、创建/获取信号量集,使用semget函数
c、初始化/操作信号量集,使用semctl/semop函数
d、如果不再使用,则删除信号量集,使用semctl函数
#include <sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
key_t key = ftok(const char *pathname, int proj_id);
参 1:字符串形式的路径名,必须关联一个存在的,并且可以访问的文件
参 2:项目的编号,必须是非零低八位二进制位
返回:成功返回生成key值,失败 —— -1
功能:主要用于根据参数指定的路径和项目编号来生成key值
注意:使用相同的路径名和相同的项目编号,生成的key值也相同
int semid = semget(key_t key, int nsems, int semflg);
参 1:key值
参 2:信号量集的大小/信号量的个数
0 —— 表示获取已经存在的信号量集
参 3:具体的操作标志 ( IPC_CREAT | IPC_EXCL | 0664 )
0 —— 表示获取已经存在的信号量集
返回:成功返回信号量集的编号,失败返回-1
功能:主要创建/获取信号量集
int semctl(int semid, int semnum, int cmd, ...);
参 1:信号量集的id,semget返回值
参 2:信号量集的下标,从零开始
参 3:具体的操作命令
SETVAL —— 使用第四个参数的数值给信号量集中下标为semnum的信号量进行(初始化)
IPC_RMID —— 删除信号量集,此时忽略第二个参数,不需要第四个参数 (删除)
参 4:可变长参数,是否需要取决于cmd
union semun {
int val; /*Value for SETVAL */
struct semid_ds *buf; /*Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
};
功能:主要用于操作指定的信号量集/信号量
int semop(int semid, structsembuf *sops, unsigned nsops);
参 1:信号量集的id,semget返回值
参 2:结构体指针,可以指向结构体变量/数组地址
struct sembuf{
unsigned shortsem_num; /* 信号量集的下标 */
short sem_op; /* 信号量的操作,整数表示增加,负数表示减少,0不变 */
short sem_flg; /* 操作的标志,默认给0 */
}
参 3:结构体指针所指向的结构体数量
功能:主要用于操作信号量集/信号量
ipcs -s —— 察看信号量集
ipcrm -s —— 删除信号量集
ipcs -a —— 察看所有的IPC结构
1 //使用信号量集实现进程间的通信 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/ipc.h> 7 #include <sys/sem.h> 8 #include <signal.h> 9 10 int semid;11 12 void fa(int signum)13 {14 15 printf("正在删除信号量集...\n");16 17 int res = semctl( semid, 0, IPC_RMID);18 19 if( -1 == res )20 {21 perror( "semctl error" );22 exit(-1);23 }24 25 sleep(3);26 27 printf("删除成功!");28 29 exit(1);30 }31 32 int main(void)33 {34 35 //1.获取key,ftok函数36 37 key_t key = ftok(".", 200);38 if(-1 == key )39 {40 perror("FTOK ERROR");41 exit(-1);42 }43 44 printf("key = %#x\n", key);45 //2.创建信号量集,使用semget函数46 semid = semget(key, 1/*信号量集的大小*/, IPC_CREAT | IPC_EXCL | 0666);47 if( -1 == semid )48 {49 perror("SEMGET ERROR");50 exit(-1);51 }52 53 printf("semid = %d \n", semid);54 //3.初始化信号量集,使用semctl函数55 //int arr[1];56 //int arr[0] = 5;57 int res = semctl(semid, 0/*信号量下标*/,SETVAL, 5/*信号量的初始值*/);58 if(-1== res)59 {60 perror("semctle");61 exit(-1);62 }63 printf("初始化信号量集成功\n");64 //4.如果不再使用,删除信号量集,semctl65 66 printf("请按ctrl+c删除信号量集\n");67 if( SIG_ERR == signal(SIGINT, fa) )68 {69 perror("SIGNAL ERROR");70 exit(-1);71 }72 73 while(1);74 75 return 0;76 }42 43 struct sembuf buf;44 buf.sem_num = 0;45 buf.sem_op = -1;46 buf.sem_flg = 0;47 48 int res = semop(semid, &buf, 1);49 if( -1 == res )50 {51 perror("semop");52 exit(-1);53 }54 55 printf("进程%d抢占共享资源成功\n", getpid() );56 57 sleep(20);58 59 buf.sem_op = 1;60 61 res = semop(semid, &buf, 1);62 if(-1 == res )63 {64 perror("semop");65 exit(-1);66 }67 68 printf("进程%d释放资源\n", getpid());
- UNIX_C 高级编程<五>
- UNIX_C 高级编程<一>
- UNIX_C 高级编程<二>
- UNIX_C 高级编程<三>
- UNIX_C 高级编程<四>
- UNIX_C 高级编程<六>
- UNIX_C 高级编程<七>
- unix_c++
- ASP 3.0高级编程(五)
- android_c++ 高级编程NDK学习笔记五
- linux高级编程五结构体
- Python高级编程(五)XML解析
- 《Unix环境高级编程》总结(五)
- (五)面向对象高级编程
- python高级编程(五)--多线程-协程
- C++高级编程(五)模板
- 小佳弱弱学习——unix环境高级编程(五)
- C# 2005 & .Net 3.0高级编程 勘误(五)
- 关于编码ansi、GB2312、unicode与utf-8的区别
- 直接插入排序
- POJ 3185 DFS
- 在二维数组中查找一个指定的数值
- std::map的机制
- UNIX_C 高级编程<五>
- android极光推送学习入门版
- cookie 和session 的区别详解
- Tomcat内存溢出 PermGen space和Java heap space
- wpa_supplicant
- 使用maven给spring项目打可直接运行的jar包(配置文件内置外置的打法)
- 华为OJ 初级:多线程
- linux 监控之CACTI
- Delphi StringGrid使用全书