管道和消息队列实现进程间通信
2017-05-08 17:41
323 查看
管道和消息队列实现进程间通信
管道和消息队列实现进程间通信管道
基础知识
函数介绍
练习内容
实现代码
消息队列
基础知识
函数介绍
练习内容
实现代码
管道
基础知识
管道就像现实中的水管,水就像数据。
管道是一种半双工的通信方式
数据只能单向流动,而且只能在具有共同祖先的进程间使用
函数介绍
int pipe(int fd[2])
功能:创建管道
参数fd关联:
一个读端:fd[0]
一个写端:fd[1]
头文件
<unistd.h>
int read(int fd, void *buf, int count);
功能:从参数fd指定的读端读取管道数据到大小为count的缓存buf中,返回实际读取到的字节数。
参数
fd:管道读端
buf:缓存区,保存读到的数据
count:读取字节数
int write(int fd, void *buf, int count);
功能:向参数fd指定的写端从缓存buf中取出count个字节到管道中,返回值为实际写入的字节数。
参数
fd:管道写端
buf:缓存区,将要写入管道的数据
count:写入的字节数
练习内容
1.父进程创建管道和两个子进程p1和p2 2.子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok",目的是通知进程p2可以读取文件内容了。 3.子进程p2通过管道读取消息,如果消息是“ok”,则打开文件,读取文件内容,并将其输出到屏幕上,关闭文件
实现代码
/*2.利用管道实现进程间的通信 编写程序,父进程创建管道和两个子进程p1和p2 子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok",目的是通知进程p2可以读取文件内容了。 子进程p2通过管道读取消息,如果消息是“ok”,则打开文件,读取文件内容,并将其输出道屏幕上**/ //管道是半双工的通信方式 //数据只能单向流动,而且只能在具有共同祖先的进程间使用。 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> //管道需要的头文件 #include <string.h> //#include <mem.h> //memset()函数 #include <fcntl.h> #define BUFFER_SIZE 1024 int write_file() //把内容写到文件里面去 { int f=open("a.txt",O_WRONLY|O_CREAT,0660);//打开指定路径的文件,如果不存在自动创建 //f为一文件指针 if(f==-1) //打开失败 { printf("open file error !\n"); return 0; } char buffer[]="this is a file";//写到文件里面去的内容 write(f,buffer,sizeof(buffer)); //向参数f指定的写端从缓存buf中取指定大小的字节到管道中 //返回值为实际写入的字节数 close(f);//关闭文件 return 1; } int read_file(char *buffer) { int f=open("a.txt",O_RDONLY,0660);//打开指定路径的文件,如果不存在自动创建 if(f==-1)//打开文件失败 { printf("open file error !\n"); return 0; } int numofchar=read(f,buffer,BUFFER_SIZE); //f代表读端 //不知道缓冲区有多少有效的数据,所以把buffer大小的内容全读出来 //从参数f指定的读端读取管道数据到指定大小为的缓存buf中 //返回实际读取到的字节数 close(f); return numofchar; } int main(int argc,char *argv[]) { int fd[2]; //创建管道的读写端(fd【0】读,fd【1】写) if(pipe(fd)<0)//创建管道 { perror("pipe");//错误输出函数,没有错误的时候就显示 error 0 exit(0); } char mas[100]; int n; memset(mas,0,sizeof(mas)); //清空buf内容为0 //一个字节一个字节的设定为指定值 //build son pid_t p1; p1=fork(); if(p1<0) //创建进程失败 { fprintf(stderr,"fork failed"); exit(-1); } else if(p1==0)//son { //子进程p1打开给定文件(如果没有,则创建文件) //并向文件中写数据,写完关闭文件,然后向管道写入一条消息“ok" //目的是通知进程p2可以读取文件内容了 if(write_file()) //调用写文件函数 { close(fd[0]); //close read char *massage = "ok"; write(fd[1],massage,100); //写管道消息 //ok 写到fd【1】里面 } } else //father { pid_t p2; p2=fork(); if(p2<0)//创建进程失败 { fprintf(stderr,"fork failed"); exit(-1); } else if(p2==0)//son { close(fd[1]); //close write read(fd[0],mas,sizeof(mas));// 从 读端读消息 if(!strcmp(mas,"ok")) // is "ok" or no { char data[BUFFER_SIZE]; int n =read_file(data); //读取文件里面的内容并存到data中 printf("data of file is : %s. \n",data);//打印出来 } } else //father { exit(0); } } return 0; }
消息队列
消息队列提供了一种由一个进程向另一个进程发送块数据的方法。每一个数据块被看作有一个类型,接收进程可以独立接收具有不同类型的数据块。
基础知识
消息队列消息的链接表,简称:队列
标识符:队列ID
队列中消息的结构:
函数介绍
int msgget(key_t key, int flag)
头文件:
<sys/msg.h>
功能:打开一个队列或创建一个新队列
返回值:一个队列id
参数:
key:标示符,也称为键。可理解为唯一的端口获取key的方法:
函数
ftok(const char* path,int id)
ftok的功能由一个路径名和项目id产生一个键
如:key = ftok(“.”, ‘t’);
flag:控制标记,指定以何种方式创建
如:0660 | IPC_CREAT
int msgsnd(int msqid, const void * ptr, size_t nbytes, int flag)
头文件:
<sys/msg.h>
功能:往消息队列写消息,即发送消息。
参数:
msqid:队列id
ptr:要发送消息的结构指针,指向消息的地址
nbytes:发送的字节数
flag:控制标记,一般指定为IPC_NOWAIT
int msgrcv(int msqid, const void * ptr, size_t nbytes ,long type, int flag) ;
头文件:
<sys/msg.h>
功能:从消息队列读消息,即接收消息。
参数:
msqid:队列id
ptr:接收的消息保存到该指针指向的消息结构
nbytes:接收的字节数
type
==0返回队列第一个消息
>0返回队列中类型为type的第一个消息
<0返回小于或等于type绝对值的消息
flag:控制标记,一般指定为IPC_NOWAIT
练习内容
父进程创建消息队列和两个子进程p1和p2 子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向消息队列写入一条消息“ok”,目的是通知进程p2可以读取文件内容了。 子进程p2从消息队列读取消息,如果收到消息“ok”,则打开文件,读取文件内容,并将其输出道屏幕上,关闭文件。
实现代码
/*父进程创建消息队列和两个子进程p1和p2 子进程p1打开给定文件(如果没有,则创建文件),并向文件中写数据,写完关闭文件,然后向消息队列写入一条消息“ok”,目的是通知进程p2可以读取文件内容了。 子进程p2从消息队列读取消息,如果收到消息“ok”,则打开文件,读取文件内容,并将其输出道屏幕上,关闭文件。*/
#include<stdio.h>
#include<sys/msg.h>
#include<fcntl.h>
#include<stdlib.h>
#include<string.h>
#define NUM 100
//消息通信
//消息队列提供了一种由一个进程向另一个进程发送块数据的方法。
//每一个数据块被看作有一个类型,接收进程可以独立接收具有不同类型的数据块。
struct mymsg
{
long mytype; //存储消息类型
char mytext[NUM];//存储消息内容
};
int main()
{
FILE *f; //文件指针
pid_t p1,p2;// 两个进程
key_t key;
key = ftok(".", 't');
//系统IPC键值的格式转换函数
char s[20];
int mgsid;
if((mgsid=msgget(key,IPC_CREAT|0666))==-1)//打开一个队列或创建一个新队列
{
printf("creat error\n");
return -1;
}
p1=fork();
if(p1<0)
{
fprintf(stderr,"fork failed");
exit(-1);
}
else if(p1==0)
{
printf("p1 pid is:%d\n",getpid()); //p1id
printf("sending the massage...\n");
sleep(1); //本线程休眠1毫秒
struct mymsg msg1;
msg1.mytype=getppid(); //父进程id
if((f=fopen("hello.txt","w"))==NULL) //打开文件失败
{
printf("the file %s not open\n","hello.txt");
return ;
}
fputs("hello!",f);//送一个字符到一个流中
fclose(f);
strcpy(msg1.mytext,"ok");
if(msgsnd(mgsid,&msg1,sizeof(msg1.mytext),0)<0)//往消息队列写消息,即发送消息。
{
printf("sending error!\n");
exit(-1);
}
else
{
printf("complete sending !\n");
exit(0);
}
}
else
{
wait(NULL);
p2=fork();
if(p2<0)
{
printf("fork creat error!\n");
exit(1);
}
else if(p2==0)
{
printf("p2 pid is:%d\n",getpid());
printf("Receiving the massage...\n");
sleep(1);//本线程休眠1毫秒
struct mymsg msg2;
msg2.mytype=getppid();
if(msgrcv(mgsid,&msg2,NUM,getppid(),0)<0)//从消息队列读消息,即接收消息
{
printf("receving error!!!\n");
exit(1);
}
else
{
printf("complete receving \n");
if(strcmp("ok",msg2.mytext)==0)
{
if((f=fopen("hello.txt","r"))==NULL)
{
printf("the file %s no opend.\n","hello.txt");
return;
}
while((fgets(s,20,f))!=NULL)//从流中读一行或指定个字符
{
printf("the massage is:%s\n",s);
}
fclose(f);
}
}
}
else
{
wait(NULL);
exit(0);
}
}
return 0;
}
本博客内容到此介绍,欢迎指正!
相关文章推荐
- 使用微软消息队列实现C#进程间通信(转)
- IPC之 - 使用微软消息队列实现C#进程间通信
- Linux进程间通信的几种方法-半双工管道,命名管道,消息队列
- 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)
- UNIX环境下如何应用消息队列实现进程间通信
- Linux进程间通信--信号,管道,消息队列,信号量,共享内存,socket
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- Linux 进程间通信——消息队列实现双向通信
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 使用微软消息队列实现C#进程间通信(二)
- 使用微软消息队列实现C#进程间通信
- UNIX环境下如何应用消息队列实现进程间通信
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 使用微软消息队列实现C#进程间通信
- 使用微软消息队列实现C#进程间通信(三)
- 现在最常用的进程间通信的方式有:管道,信号,信号量,消息队列,共享内存。
- 消息队列实现进程间通信
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
- 使用微软消息队列实现C#进程间通信
- 使用微软消息队列实现C#进程间通信