c语言系统编程七:Linux进程间通信之有名管道

一 有名管道的概述

  1. 主要用于没有血缘关系的进程间通信;
  2. 有名管道实际上是一块物理内存;无名管道是逻辑内存;
    在这里插入图片描述

二 有名管道的特点

1. 半双工,数据只能在一个方向上流动;
2. 写入FIFO中的数据遵循先入先出的规则;
3. FIFO所传输的数据是无格式的,这要求FIFO的读出方与写入方必须事先约定好数据格式,如多少字节算一个消息等;
4. FIFO在文件系统中作为一个特殊文件存在,但FIFO中的内容是存放在内存中的;
5. 管道在内存中对应一个缓冲区,不同的系统其大小不一定相同;
6. 从FIFO读数据是一次性操作,读完就从FIFO中被抛弃;
7. 当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用;
8. FIFO有名字,不相关的进程可以通过打开命名管道进行通信

三 有名管道的API

3.1 创建有名管道

  1. 需要的头文件和函数原型
#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);
  1. 参数
pathname:FIFO的路径名+文件名
mode:权限描述符
  1. 返回值
成功:返回0
失败:如果文件已经存在,则会出错并返回-1

四 有名管道案例

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

int main(int arg, char *argv[])
{
	//创建有名管道
	mkfifo("/root/myfifo1",0666);
#ifdef READ
	int fd = open("/root/myfifo1",O_RDONLY);
#endif
#ifdef WRITE
	int fd = open("/root/myfifo1",O_WRONLY);
#endif
	if(fd<0)
	{
		perror("open");
		return 0;
	}
#ifdef READ
	printf("读端open成功了\n");
	while(1)
	{
		char buf[1024] = "";
		read(fd,buf,sizeof(buf));
		printf("收到数据:%s\n",buf);
		if(strcmp(buf,"bye") == 0)
			break;

	}
#endif
#ifdef WRITE
	printf("写端open成功了\n");
	while(1)
	{
		printf("请输入:");
		char buf[1024] = "";
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1] = 0;
		write(fd,buf,strlen(buf));
		if(strcmp(buf,"bye") == 0)
			break;

	}
#endif
	close(fd);
	return 0;
}

在这里插入图片描述

五 有名管道读写特点

以阻塞方式打开管道:
1. open函数以只读方式打开有名管道时,要阻塞直到有其他进程以写方式打开这个管道;
2. open函数以只写方式打开有名管道时,要阻塞直到有其他进程以读方式打开这个管道;
3. 调用read函数从有名管道读数据时,read会阻塞;
4. 通信过程中如果写进程先退出,则调用read函数从有名管道读数据时不阻塞;如果写进程又重新运行,则调用read函数又恢复阻塞;
5. 读进程退出后,写进程向管道写时会收到SIGPIPE信号而退出;
6. 调用write函数向管道写数据时,如果缓冲区满了,write会阻塞
以非阻塞方式打开管道:
7. 先以只读方式打开:如果没有进程已经为写而打开一个FIFO,只读open成功,而且open不阻塞;
8. 先以只写方式打开:如果没有进程已经为读而打开一个FIFO,只写open将出错返回-1;
9. read,write读写命名管道中数据时不堵塞;
4.通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会收到SIGPIPE信号而退出;
注意: open函数以可读可写方式打开FIFO文件时的特点:
1. open不阻塞;
2.调用read函数从FIFO里读取数据时read会阻塞;
3. 调用write函数向FIFO里写数据,当缓冲区已满时write也会阻塞

六 命名管道实例-单机qq聊天

实现单机QQ聊天。提示:父进程创建子进程,实现多任务。父进程负责发消息(向FIFO里写数据),子进程负责接收信息(从FIFO里读数据)。打开命名管道用阻塞方式打开。

在这里插入图片描述

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

int main(int arg, char *argv[])
{
	//创建有名管道
	mkfifo("./andytolinda",0666);
	mkfifo("./lindatoandy",0666);

	//创建两个子进程用管道通信
	int i = 0;
	for(i=0;i<2;i++)
	{
		pid_t pid = fork();
		if(pid == 0)
			break;
	}

	if(i==0) //子进程1  负责写
	{
#ifdef andy
		int fd = open("./andytolinda",O_WRONLY);
#endif
#ifdef linda
		int fd = open("./lindatoandy",O_WRONLY);
#endif
		if(fd==-1)
		{
			perror("open");
			return 1;
		}
		while(1)
		{
#ifdef andy
			printf("\rAndy: ");
#endif
#ifdef linda
			printf("\rLinda: ");
#endif
			char buf[128]="";
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1]=0;
			write(fd,buf,strlen(buf));
			if(strcmp(buf,"bye")==0)
				break;
		}
		close(fd);
		_exit(0);

	}
	else if(i == 1) //子进程2  负责读
	{
#ifdef andy
		int fd = open("./lindatoandy",O_RDONLY);
#endif
#ifdef linda
		int fd = open("./andytolinda",O_RDONLY);
#endif
		if(fd==-1)
		{
			perror("open");
			return 1;
		}
		while(1)
		{
			char buf[128]="";
			read(fd,buf,sizeof(buf));
#ifdef andy
			printf("\rLinda said: %s\n\rAndy:",buf);
#endif
#ifdef linda
			printf("\rAndy said: %s\n\rLinda:",buf);
#endif
			if(strcmp(buf,"bye")==0)
				break;
		}
		close(fd);
		_exit(0);
			
	}
	else if(i == 2) //父进程
	{
		while(1)
		{
			pid_t pid = wait(NULL);
			if(pid > 0)
				printf("主进程回收了子进程:%d\n",pid);
			else if(pid < 0)
				break;

		}
	}	

	return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值