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

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

Linux进程间通信之有名管道
  • 一 有名管道的概述
  • 二 有名管道的特点
  • 三 有名管道的API
    • 3.1 创建有名管道
  • 四 有名管道案例
  • 五 有名管道读写特点
  • 六 命名管道实例-单机qq聊天

一 有名管道的概述
  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 
#include 

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

四 有名管道案例
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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;
}

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/1498634.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-25
下一篇2022-06-25

发表评论

登录后才能评论

评论列表(0条)

    保存