一、
浅谈进程通信和管道
谈到进程间通信,就是在数据上不同进程上的共享,让不同的进程看到同一份物理内存。此过程必须通过内核(就是同常意义上的操作系统),在内核中开辟一块缓冲区,把进程1的数据拷入内核的缓冲区,进程2再从内核的缓冲区读取数据,实现进程间通信IPC。
而通过管道进行通信的实质是父进程通过fork()函数创建子进程,子进程获得了父进程的文件描述符的副本,从而共享数据,进程实现通信。
●文件描述符
文件描述符是一个较小的正整数,标明每一个被打开进程的文件和socket,通过open()函数和creat()函数,获取或从父进程中继承,0表示标准输入stdin,1表示标准输出stdout,2表示标准错误 stderror.
●管道pipe
头文件:<unistd.h>
函数原型:int pipe (int fileds[2])
此函数是linux内核提供的系统接口,调用pipe()函数在内核中开辟一块缓冲区,通过fileds[]参数传入两个文件描述符,f[0]为读出端,f[1]为写入端。使用read()函数和write()函数对操作内核缓冲区。pipe()函数创建失败返回-1.
●管道pipe的特点
1、管道是单向通信的,若要建立双向通信,需建立多个管道;
2、管道是基于字节流通信的;
3、生命周期依赖于文件系统,随进程的结束而结束;
4、自带有协调体同步,互斥效果,保证通信的完整性。
5、管道的容量一般为64k,随内核而改变,是由环形队列组成的。
6、只能作用于有血缘关系的进程,常用于父子进程。
代码实现
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
int fds[2]={
0,0
};
if(pipe(fds)<0)
0,0
};
if(pipe(fds)<0)
{
printf("pipe error.%s\n",strerror(errno));
return 2;
}
pid_t id=fork(); //创建子进程
if(id==0)
printf("pipe error.%s\n",strerror(errno));
return 2;
}
pid_t id=fork(); //创建子进程
if(id==0)
{
close(fds[0]); //子进程写数据
int count=2;
char* msg="hello world\n";
while(count--)
{
write(fds[1],msg,strlen(msg));
printf("write success. %d\n");
close(fds[0]); //子进程写数据
int count=2;
char* msg="hello world\n";
while(count--)
{
write(fds[1],msg,strlen(msg));
printf("write success. %d\n");
}
close(fds[1]);
}
else{
close(fds[1]);
}
else{
close(fds[1]); //父进程读数据
int count=0;
char buf[1024];
while(count++<3){
int count=0;
char buf[1024];
while(count++<3){
ssize_t s=read(fds[0],buf,sizeof(buf)-1);
if(s>0)
{
buf[s]='\0';
if(s>0)
{
buf[s]='\0';
}
printf("father msg :%s",buf);
if(waitpid(id,NULL,0)<0)
{
return 3;
printf("father msg :%s",buf);
if(waitpid(id,NULL,0)<0)
{
return 3;
}
}
}
return 0;
}
return 0;
}
●命名管道FIFO
可以使任意进程见通信,通过访问路径,按先进先出的方式处理数据
mkfifo函数的作⽤用是在⽂文件系统中创建⼀一个⽂文件,该⽂文件⽤用于提供FIFO功能,命名管道。 前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对⽂文件系统来说, 匿名管道是不可见的,它的作⽤用仅限于在⽗父进程和⼦子进程两个进程间进⾏行通信。⽽而命名管 道是⼀一个可见的⽂文件,因此,它可以⽤用于任何两个进程之间的通信。
头文件:
<sys/types.h>
<sys/stat.h>
创建命名管道函数原型:
int mkfifo(const char* pathname,mode_t mode)
pathname为路径,命名管道的名称,mode为访问权限
fifo为读端
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
umask(0);
if(mkfifo("./fifo",S_IFFO|0666)!=0)
{
perror("fifo error");
return 1;
}
{
perror("fifo error");
return 1;
}
int fd=open("./fifo",O_RONLY);
if(fd < 0)
{
printf("open error!\n");
return 1;
}
char buf[1024];
memset(buf, '\0', sizeof(buf));
while(1)
{
int ret = read(fd, buf, sizeof(buf));
if (ret <= 0) //error or end of file
{
printf("read error!\n");
break;
}
printf("%s\n");
if( strncmp(buf, "quit", 4) == 0 )
break;
}
}
close(fd);
return 0;
}
fifo为写端
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
int main()
{
int fd=open("./fifo",O_WRONLY);
if(fd>0)
{
perror("open error");
}
char arry[1024]
while(1)
{
printf("start!\n");
fflush(stdout);
ssize_t r=read(0,arry,sizeof(arry)-1);
if(r>0)
{
arry[r]='\0';
write(fd,strlen(arry));
}
printf("quit");
break;
}
return 0;
}
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
int main()
{
int fd=open("./fifo",O_WRONLY);
if(fd>0)
{
perror("open error");
}
char arry[1024]
while(1)
{
printf("start!\n");
fflush(stdout);
ssize_t r=read(0,arry,sizeof(arry)-1);
if(r>0)
{
arry[r]='\0';
write(fd,strlen(arry));
}
printf("quit");
break;
}
return 0;
}