linux中匿名管道和命名管道

本文深入探讨了管道通信机制,包括匿名管道的工作原理及其四种关键场景的行为表现,并通过示例代码展示了不同情况下管道通信的过程。此外,还介绍了命名管道的实现方式及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

管道

匿名管道

1、创建管道和父子进程,子进程关闭读端,父进程关闭写端,子进程写,父进程读。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int pipefd[2] = {0,0};
if(pipe(pipefd) < 0){
perror("pipe");
return 1;
}
pid_t id = fork();// creat child progress
if(id < 0){
perror("fork");
return 2;
}else if(id == 0){//child->write
close(pipefd[0]);
const char* msg = "hello world";
int count = 5;
while(count){
write(pipefd[1],msg,strlen(msg));
count--;
sleep(1);
}
close(pipefd[1]);
exit(0);


}else{//father->read
close(pipefd[1]);
int count = 5;
char buf[128];
while(count){
ssize_t _s = read(pipefd[0],buf,sizeof(buf)-1);
if(_s > 0){
buf[_s] = '\0';
printf("%s\n",buf);
}else if(_s == 0){
printf("close\n");
break;
}else{
perror("read");
return 3;
}
count--;
}
close(pipefd[0]);
}
return 0;
}


2、如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程 从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int pipefd[2] = {0,0};
if(pipe(pipefd) < 0){
perror("pipe");
return 1;
}
pid_t id = fork();// creat child progress
if(id < 0){
perror("fork");
return 2;
}else if(id == 0){//child->write
close(pipefd[0]);
const char* msg = "hello world";
int count = 5;
while(count){
write(pipefd[1],msg,strlen(msg));
count--;
sleep(1);
}
close(pipefd[1]);
exit(0);


}else{//father->read
close(pipefd[1]);
int count = 5;
char buf[128];
while(1){
ssize_t _s = read(pipefd[0],buf,sizeof(buf)-1);
if(_s > 0){
buf[_s] = '\0';
printf("child->father:%s\n",buf);
}else if(_s == 0){
printf("pipe write is close\n");
break;
}else{
perror("read");
return 3;
}
count--;
}
close(pipefd[0]);
}
return 0;
}


3、如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的 进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int pipefd[2] = {0,0};
if(pipe(pipefd) < 0){
perror("pipe");
return 1;
}
pid_t id = fork();// creat child progress
if(id < 0){
perror("fork");
return 2;
}else if(id == 0){//child->write
close(pipefd[0]);
const char* msg = "hello world";
int count = 5;


while(1){
write(pipefd[1],msg,strlen(msg));
count--;
if(count == 0)
{
sleep(5);
count--;
}
sleep(1);
}
close(pipefd[1]);
exit(0);
}else{//father->read
close(pipefd[1]);
int count = 5;
char buf[128];
while(1){
ssize_t _s = read(pipefd[0],buf,sizeof(buf)-1);
if(_s > 0){
buf[_s] = '\0';
printf("child->father:%s\n",buf);
}else if(_s == 0){
printf("pipe write is close\n");
break;
}else{
perror("read");
return 3;
}
count--;
}
close(pipefd[0]);
}
return 0;
}


4、如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int pipefd[2] = {0,0};
if(pipe(pipefd) < 0){
perror("pipe");
return 1;
}
pid_t id = fork();// creat child progress
if(id < 0){
perror("fork");
return 2;
}else if(id == 0){//child->write
close(pipefd[0]);
const char* msg = "hello world";
int count = 5;


while(1){
write(pipefd[1],msg,strlen(msg));
count--;
sleep(1);
}
close(pipefd[1]);
exit(0);
}else{//father->read
close(pipefd[1]);
int count = 5;
char buf[128];
while(1){
ssize_t _s = read(pipefd[0],buf,sizeof(buf)-1);
if(_s > 0){
buf[_s] = '\0';
printf("child->father:%s\n",buf);
}else if(_s == 0){
printf("pipe write is close\n");
break;
}else{
perror("read");
return 3;
}
count--;
if(count == 0){
close(pipefd[0]);
break;
}
}
}
int status = 0;
pid_t ret = waitpid(id,&status,0);
if(ret > 0){
printf("exit code: %d,signl: %d\n",(status>>8)&0xff,status&0xff);
}
return 0;
}


命名管道

1、client端

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
int main()
{

int fd = open("./fifo",O_WRONLY);
if(fd < 0){
perror("open");
return 2;
}
char buf[128];
while(1){
printf("Please Enter# ");
fflush(stdout);
ssize_t s = read(0,buf,sizeof(buf));
if(s > 0){
buf[s-1] = '\0';
write(fd,buf,strlen(buf));
}else if(s == 0){
printf("client quit! I should quit!\n");
break;
}else{
perror("read");
}
}
close(fd);
return 0;
}

2、server端

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
int main()
{
umask(0);
if(mkfifo("./fifo",0666|S_IFIFO) < 0){
perror("mkfifo");
return 1;//shell look
}


int fd = open("./fifo",O_RDONLY);
if(fd < 0){
perror("open");
return 2;
}
char buf[128];
while(1){
ssize_t s = read(fd,buf,sizeof(buf));
if(s > 0){
buf[s] = '\0';
printf("client# %s\n",buf);
}else if(s == 0){
printf("client quit! I should quit!\n");
break;
}else{
perror("read");
}
}
close(fd);
return 0;
}

client端输入什么,server端输出什么,结果如下所示:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值