您的位置:首页 > 其它

进程通信之管道

2018-03-28 16:14 127 查看

管道

管道是UNIX系统IPC的最古老形式,并且所有UNIX系统都提供此种通信机制,我们把一个进程连接到另一个进程的数据流称为管道,在管道中一个进程写,一个进程读。



管道的本质也就是操作系统内核提供的一段内存。

管道在创建时获得固定字节数的大小,当一个进程往里面写时,如果有空间,写请求立即执行,否则该进程被阻塞。类似的,如果一个进程试图读取多于当前管道的字节数时,也会阻塞。

管道有两类:匿名管道和命名管道

匿名管道

匿名管道的操作必须是有两个亲缘关系的进程

管道是调用pipe函数创建的:

int pipe(int fd[2])


fd是一个文件描述符数组,fd[0]表示读端,fd[1]表示写端

成功返回0,失败返回小于0的错误代码

下面一段匿名管道创建的代码:

#include<stdio.h>
#include<string.h>
#include<unistd.h>

void Test1()
{
int fd[2];
int ret = pipe(fd);
if(ret <  0)
{
perror("pipe");
return;
}

//通过fork创建子进程,父进程从管道一端写,子进程从管道读
int pid = fork();

const char* str = "hello\n";
if(pid > 0)
{
//father write
close(fd[0]);//父进程只写,所以关闭读端的文件描述符
write(fd[1],str,strlen(str));
close(fd[1]);
printf("father:%d\n",getpid());
}
else if(pid == 0)
{
//child read
close(fd[1]);//子进程只读,所以关闭写端的文件描述符
char buf[1024] = {0};
read(fd[0],buf,sizeof(buf)-1);//-1操作是为了给'\0'预留位置
close(fd[0]);
printf("child:%d ,%s\n",getpid(),buf);

}
else
perror("fork");
sleep(1);
}


用frok共享管道原理:



注意:当数据被读走后,数据就会被管道释放,以便继续接收更多的数据。

管道结构

在底层实现总,管道的实现是两个进程的f_inode指向同一个临时的inode节点,这个节点指向一个物理页面



因此,对管道的操作也就是对文件的操作,通过不同的文件描述符来标识不同的文件

命名管道

命名管道不需要进程之间有任何关系便能完成通信。

创建一个命名管道:

mkfifo filename

也可以通过函数创建

int mkfifo(const char*filename,mode_t mode);


代码实现:

client.c

#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>

int main()
{
int ret = open("./mypipe",O_WRONLY);
if(ret < 0)
{
perror("open");
exit(1);
}
char buf[1024] = {0};
while(1)
{
printf(">:");
fflush(stdout);
ssize_t read_size = read(0,buf,sizeof(buf)-1);
if(read_size > 0)
{
buf[read_size] = '\0';
write(ret,buf,strlen(buf));
}
else
{
perror("read");
continue;
}
}
return 0;
}


server.c

#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<stdio.h>

int main()
{
int ret = open("./mypipe",O_RDONLY);
if(ret < 0)
{
perror("open");
exit(1);
}
char buf[1024] = {0};
while(1)
{
ssize_t read_size = read(ret,buf,sizeof(buf)-1);
if(read_size < 0)
{
perror("read");
continue;
}
else if(read_size == 0)
{
printf("一个客户端退出\n");
break;
}
else
{
buf[read_size] = '\0';
printf("[client]:");
fflush(stdout);
write(1,buf,strlen(buf));
}

}
close(ret);
return 0;
}


mkfifo创建一个命名管道:

用命名管道实现服务器/客户端之间的通信,满足:客户端从标准输入读取信息,通过命名管道发送给服务器端,服务器端将其输出到屏幕上。

管道的特点

单向通信

面向字节流

aaf4

缓冲区大小有限制

生命周期根随进程

管道有容量限制

管道内部具有同步机制(同时只能由一个进程读写)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息