目录
前言
进程间通信的目的:
1、数据传输:一个进程需要将它的数据发送给另一个进程
2、资源共享:多个进程之间共享同样的资源
3、通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)
4、 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常
进程间通信:IPC(InterProcess Communication)
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等,其中Socket和Streams支持不同主机上的两个进程IPC。
一、管道
管道,通常指无名管道,是UNIX系统IPC最古老的形式
特点:
1、半双工(即数据只能在一个方向流动),具有固定的读端和写端
2、只用于父子进程和兄弟进程之间通信
3、可看成一种特殊的文件,对于它的读写可以使用普通的read、write函数,但它不是普通文件,并不属于任何文件系统,并只存在内存中
4、同一时间,数据只能是单向的,一边读一边写
5、管道的数据,读走就没
(1)无名管道
NAME
pipe, pipe2 - create pipe
SYNOPSIS
#include <unistd.h>
int pipe(int pipefd[2]);
##int pipefd[2] 定义一个两个元素的数组
代码实现:
#include<stdio.h>
#include <unistd.h>
#include<string.h>
#include <stdlib.h>
int main ()
{
int fd[2];
int pid;
char readBuf[128]={0};
if(pipe(fd)==-1){
printf("creat pipe fail\n");
}
pid=fork();
if(pid<0){
printf("creat fail\n");
}else if(pid>0){//进入父进程
sleep(1);
printf("this is father\n");
close(fd[0]);//关闭读端
write(fd[1],"hello helloo",strlen("hello helloo"));//把数据写入管道
}else{//进入子进程
printf("this is child\n");
close(fd[1]);//关闭写端
read(fd[0],readBuf,128);//读取缓冲区数据
printf("%s\n",readBuf);//输出数据
}
return 0;
}
执行成功。
(2)命名管道
FIFO,也称为命名管道,它是一种文件类型
特点:
1、FIFO可以在无关的进程之间交换数据,与无名管道不同
2、FIFO有路径名与之关联,它以一种特殊设备文件形式存在于文件系统中
函数原型:
NAME
mkfifo - make a FIFO special file (a named pipe)
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
##第一个参数是创建管道的名字
##第二个参数是创建管道的权限
创建命名管道,代码如下:
if((mkfifo("./file",0600)==-1) && errno!=EEXIST){
//若命名管道文件创建失败且管道文件不存在输出错误信息
printf("mkfifo error\n");
perror("why");
}
使用命名管道实现进程间通信
读端:
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
int main(){
int fd;
char readBuf[30]={0};
if((mkfifo("./file",0600)==-1) && errno!=EEXIST){
printf("mkfifo error\n");
perror("why");
}
fd=open("./file",O_RDONLY);
int nread=read(fd,readBuf,30);
printf("have %d ,context is %s\n",nread,readBuf);
close(fd);
return 0;
}
写端:
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include<string.h>
#include <fcntl.h>
int main(){
int fd;
char *str="hello hello";
fd=open("./file",O_WRONLY);
write(fd,str,strlen(str));
close(fd);
return 0;
}
二、消息队列
消息队列,是消息的链接表,存放在内核中,一个消息队列由一个标识符(即队列ID)来标识。
特点:
1、消息队列是面向记录的,其中的消息具有特定的格式一级特定的优先级
2、消息队列独立于发送与接受进程。进程终止时,消息队列及其内容并不会被删除
3、消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
创建消息队列
#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|0777
成功返回队列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);
成功返回0,失败返回-1
int msqid: 消息队列标识符
const void *msgp: msgp是一个任何类型的结构体,是消息队列的地址
size_t msgsz: 要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度
int msgflg: 默认写0,当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
const void *msgp的结构体如下:
struct msgbuf{
long mtype; //message type,must be>0
char mtext[128]; //message data
}
读取消息队列
#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);
成功返回消息数据的长度,失败返回-1
int msqid :消息队列标识符
void *msgp :存放消息队列的结构体,结构体类型要与msgsnd函数发送的类型相同
size_t msgsz : 要接受消息的大小,不含消息类型占用的4个字节
long msgtyp :要读消息的类型,如写:888
int msgflg :默认写0:阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
控制消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msqid :消息队列标识符
int cmd : IPC_RMID删除节点 用的最多
struct msqid_ds *buf :NULL
ftok函数
系统建立IPC通讯(消息队列、信号量、共享内存)时必须制定一个ID值。通常情况下,该ID值通过ftok函数得到。
key_t key;
key=ftok(".",1);
第二空参数可以为任意数值
实现消息队列的接收和发送
接收信息:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
struct msgGet {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(){
struct msgGet readBuf;
int msgId=msgget(0x1234,IPC_CREAT|0777);
if(msgId==-1){
printf("creat queue fail\n");
}
msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888,0);
printf("context is %s\n",readBuf.mtext);
return 0;
}
发送信息:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
struct msgSend {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(){
struct msgSend sendBuf={888,"this is senddata! haha"};
int msgId=msgget(0x1234,IPC_CREAT|0777);
if(msgId==-1){
printf("creat queue fail\n");
}
msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext),0);
return 0;
}
实现相互发送接收,两者同理
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
struct msgSend {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(){
struct msgSend sendBuf={888,"this is senddata! haha"};
key_t key;
key=ftok(".",1);
int msgId=msgget(key,IPC_CREAT|0777);
if(msgId==-1){
printf("creat queue fail\n");
}
msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext),0);
struct msgSend readBuf;
msgrcv(msgId,&readBuf,sizeof(readBuf.mtext),988,0);
printf("context is %s\n",readBuf.mtext);
msgctl(msgId,IPC_RMID,NULL);
return 0;
}
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<stdio.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// int msgflg);
struct msgGet {
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(){
struct msgGet readBuf;
key_t key;
key=ftok(".",1);
int msgId=msgget(key,IPC_CREAT|0777);
if(msgId==-1){
printf("creat queue fail\n");
}
msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888,0);
printf("context is %s\n",readBuf.mtext);
struct msgGet sendBuf={988,"thank you for reach"};
msgsnd(msgId,&sendBuf,sizeof(sendBuf.mtext),0);
msgctl(msgId,IPC_RMID,NULL);
return 0;
}