Linux——IPC 基于文件的通信(普通文件 管道文件)

一.基于文件的通信

    1.普通文件(io方式读取/mmap内存映射方式)
    2.有名管道文件
    3.匿名管道
    4.Socket

procA.c//往普通文件写数据

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
main()
{
	int *p;
	int fd;
	int i;
	fd=open("tmp",O_RDWR|O_CREAT,0666);
	ftruncate(fd,4);
	p=mmap(0,4,PROT_READ|PROT_WRITE,
			MAP_SHARED,fd,0);
	i=0;		
	while(1)
	{
		sleep(1);
		*p=i;
		i++;
	}
	close(fd);
}

procB.c//往普通文件读数据

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
main()
{
	int *p;
	int fd;	
	fd=open("tmp",O_RDWR);	
	p=mmap(0,4,PROT_READ|PROT_WRITE,
			MAP_SHARED,fd,0);
	while(1)
	{
		sleep(1);
		printf("%d\n",*p);
	}
	close(fd);
}


                1.1.无序文件
                1.1.有序文件
                        1.1.1.管道
                                1.1.1.1.有名
                                1.1.1.2.匿名
                        1.1.2.socket
        2.基于内存
                2.1.无序内存
                        2.1.1.匿名内存
                        2.1.2.共享内存
                2.2.有序内存
                        2.2.1.共享队列
        3.同步:基于内存IPC应用(共享内存数组)
                信号量/信号灯
                

二.基于普通文件的IPC

        IPC的技术提出的应用背景.
        进程之间需要同步处理:
        同步需要通信.
        普通文件就是最基本的通信手段.
        普通文件IPC技术的问题:
                一个进程改变文件,另外一个进程无法感知.
        解决方案:
                    一个特殊的文件:管道文件

三.基于管道文件的IPC

        1.创建管道mkfifo
        2.体会管道文件特点 不能使用映射区读写 只能使用原始的
    案例:                                
            fifoA                fifoB
            建立管道                        
            打开管道            打开管道
            写数据                读数据
            关闭管道            关闭管道

            删除管道

fifoA.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdlib.h>
int fd;
int i;
void  end(int s)
{
	//关闭管道
	close(fd);		
	//删除管道
	unlink("my.pipe");
	exit(-1);
} 

main()
{
	signal(SIGINT,end);	
	//建立管道
	mkfifo("my.pipe",0666);//文件大小是0,虚拟的 数据都在内存
	//打开管道
	fd=open("my.pipe",O_RDWR);
	//shutdown(fd,SHUT_RD);
	i=0;
	while(1)
	{
		//每隔1秒写数据
		sleep(1);
		write(fd,&i,4);
		i++;
	}
	
}

fifoB.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdlib.h>
int fd;
void end(int s)
{
	//关闭管道
	close(fd);
	exit(-1);
}
main()
{
	int i;	
	//打开管道
	signal(SIGINT,end);
	fd=open("my.pipe",O_RDWR);
	//shutdown(fd,SHUT_WR);
	while(1)
	{
		read(fd,&i,4);
		printf("%d\n",i);
	}	
}



                
    建立管道文件:

            使用linux的指令mkfifo

            在程序中有个函数

    
    总结:
            1.read没有数据read阻塞,而且read后数据是被删除
            2.数据有序
            3.打开的描述符号可以读写(two-way双工)
            4.管道文件关闭后,数据不持久.(A管道关闭后里面的数据丢失)

            5.管道的数据存储在内核缓冲中 打开时候文件目录中的管道符号文件就没有意义了

             比如将它删除 B进程并不出错 只是阻塞, 写往管道的数据并不是在文件里而是在内存里

四.匿名管道

        发现有名的管道的名字仅仅是内核识别是否返回同一个fd的标示.
        所以当管道名失去表示作用的时候,实际可以不要名字
.
                    
        在父子进程之间:打开文件描述后创建进程.
        父子进程都有描述符号.    管道文件没有价值.
        所以在父子进程中引入一个没有名字的管道:匿名管道.
        结论:
                匿名管道只能使用在父子进程.
        
        1.创建匿名管道
        2.使用匿名管道
案例:
        匿名管道的创建
        体会匿名管道的特点
        int pipe(int fd[2]);//创建管道.打开管道.拷贝管道.关闭读写        
        fd[0]:只读(不能写)
        fd[1]:只写(不能读)    
        

        注意:数据无边界.

demo.2

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
main()
{
	int fd[2];
	pipe(fd);
	if(fork())
	{//parent
		close(fd[0]);//只负责写
		while(1)
		{
			write(fd[1],"Hello",5);
			sleep(1);
		}
	}
	else
	{//child
		char buf[20];
		int r;
		close(fd[1]);//只负责读
		while(1)
		{
			r=read(fd[0],buf,20);
			buf[r]=0;
			printf("::%s\n",buf);
		}
	}
}


        
综合:
        建立两个子进程:
            一个负责计算1-5000的素数
            另外一个负责计算5001-10000

            父进程负责存储

demo3.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
int idx=0;
int fddata;
void handle(int s)
{
	int status;
	if(s==SIGCHLD)
	{
		wait(&status);		
		idx++;
		if(idx==2)
		{
			close(fddata);
			printf("任务完成\n");
			exit(-1);
		}
	}
}
int isprimer(int ta)
{
	int i=2;
	for(;i<ta;i++)
	{
		if(ta%i==0)
		{
			return 0;
		}
	}
	return 1;
}
main()
{
	int a,b;
	int id=1;
	int fd[2];
	signal(SIGCHLD,handle);
	pipe(fd);
	while(1)
	{
		if(id==1){
			a=2;b=50000;
		}
		if(id==2){
			a=50001;b=100000;
		}
		if(fork()){			
			id++;
			if(id>2){
				break;
			}
			continue;
		}
		else{
			//子进程
			int i;
			close(fd[0]);
			for(i=a;i<=b;i++)
			{
				if(isprimer(i))
				{
					write(fd[1],&i,sizeof(int));
					sched_yield();	
				}
							
			}
			printf("%d任务完成!\n",getpid());
			exit(0);
		}
	}
	int re;
	char buf[20];
	//打开文件,准备存储
	close(fd[1]);
	fddata=open("result.txt",
			O_RDWR|O_CREAT,0666);
	while(1)
	{			
		read(fd[0],&re,sizeof(int));
		sprintf(buf,"%d\n",re);
		write(fddata,buf,strlen(buf));
		sched_yield();
	}
	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值