C语言进程间通信

进程间通信:
1: 资源共享 --- 
2: 数据传输 --- 发送接受信息
3: 通知事件 --- 信号
4: 进程控制 --- 控制进程状态转换

比较古老:
无名管道(PIPE)
有名管道(FIFO ,named pipe)
信号(signal)

SYSTEM V IPC
信号量(Sem)
共享内存(shm)
消息队列(Msg)

BSD 
套接字(Socket)---- 网络编程

无名管道(PIPE)

int fd[2];
读0写1 -- 只能往read fd[0] , write [1];

open(无) --->  pipe 已有创建并打开功能
read / write / close 

无名管道只能用在有亲缘关系的进程中,进程结束了也随之消失( 局限)
一定是先pipe申请管道,才去fork子进程
1:无名管道有大小限制(4096B), 只要有空位,就可以往里面写数据,--- -- 不能保证数据的原子性
  写满后只能等到有数据被读出才能继续写入
2: 读数据是一定要读到数据才能返回的,否则就会等待
3:只有确定不再需要使用该管道的读或者写功能才能关闭close, 否则关了后就没法再open使用
4:全部进程中必须有一个fd[0]是没有关闭的,才能write进数据; 
  如果fd[0]全关了,write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程
  实例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

void sig_isr(int sig)
{
	printf("catch a SIGPIPE %d \n", sig);
	//exit(0);
}


int main(void)
{
	pid_t pid;
	int fd[2];
	char buf[100];
	
	if(pipe(fd) == -1)
	{
		perror("pipe error");
		exit(1);
	}
	printf("fd[0] = %d , fd[1]= %d\n", fd[0], fd[1]); //输出3,4。按顺序1,2被用了
	
	if((pid = fork())< 0)
	{
		perror("fork error");
		exit(1);
	}
	else if(pid == 0)// read
	{
		// 读0写1 -- read fd[0] , write [1];
		close(fd[1]);// 写端关闭
		
		printf("ready to read...\n");
		read(fd[0], buf, 100); // 等待
		printf("%s \n", buf);
		/*如果上面没有read等待主进程的write,就关闭了f[0]
		那write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程*/
		close(fd[0]);
		_exit(0);	
	}
	else // write
	{	
		signal(SIGPIPE , sig_isr);
		sleep(1);// for check read's hangup
		close(fd[0]);//进程间的通信,关闭不需要的,留下的在同一个管道里通信。
		printf("start write\n");
		write(fd[1], "hello world \n", 100);
		printf("end write\n");
		close(fd[1]);
		wait(NULL);
		printf("exit\n");
		exit(0);
	}
}
有名管道(FIFO ,named pipe)

FIFO 是有一个具体的文件的

mkfifo FIFO -m 0666 --- shell指令去创建
mkfifo("path", 0666) --使用函数去创建,mode&~umask

操作:open / close /read / write
是可以在任意两个进程中通信

open(“path” , )
O_RDONLY 
O_WRONLY
O_RDWR  (FIFO不要用RDWR)
| O_APPEND  (和wr一起用,追加)
| O_TRUNC   (和wr一起用,覆盖,直接清空后再写入,对于FIFO或者设备文件无效)
|O_CREAT|O_EXCL (如果已经存在,会返回失败; FIFO不能用open里面的CREAT创建)
|O_NONBLOCK 
  读写方式|写的方式 |创建并检查 |不阻塞

open(fifo , O_WRONLY|O_NONBLOCK)   看下能否以只写方式打开,不能就马上返回一个失败,比如在没有进程用只读方式打开时候,就会失败

1:open(fifo, O_RDONLY); 
  open(fifo, O_WRONLY);
不管先运行哪个,都会等另一个进程把对应连接打开时候才open结束
 reader 的 open会等到writer的open  运行起来才open结束,
 反之亦然

2:open(fifo, O_RDONLY|O_NONBLOCK );  就不等待writer打开文件了

3:open(fifo , O_WRONLY|O_NONBLOCK):
如果没有reader打开该管道文件的话,就直接报错,退出进程
用perror去抓信息,得到的会是No such device or address
注意:
1:管道有大小限制(4096B), 在写入数据之前,会先判断管道大小是否足够,若不够就不会写入 -- 保证了数据的原子性
  写满后只能等到有数据被读出才能继续写入
2: read读数据是一定要读到数据才能返回的,否则就会等待
3:全部进程中必须有一个reader是没有关闭的,才能write进数据; 
    如果reader全关了,write的时候内核会发一个信号 SIGPIPE, 进程对于SIGPIPE的默认操作是终止进程
4:如果writer设置成非阻塞, 就必须先运行reader,否则无法通信,见open(fifo , O_WRONLY|O_NONBLOCK):

unlink()删除已经不再需要使用的文件,避免造成垃圾文件,对应的是mkfifo创建

实例:

fifoReader.c

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

#define FIFO "/root/c/process/ififo"

int main(void)
{
	int fd;
	char buf[128];

	if(mkfifo(FIFO, 0666))//创建管道文件
	{
		 perror("Mkfifo error");
	}
	printf("open for reading... \n");
//	fd=open(FIFO,O_RDONLY);//阻塞
	fd=open(FIFO,O_RDONLY|O_NONBLOCK);//非阻塞
	/*
	1:open(fifo, O_RDONLY); 
		   open(fifo, O_WRONLY);
			不管先运行哪个,都会等另一个进程把对应连接打开时候才open结束
			  reader 的 open会等到writer的open  运行起来才open结束,
			  反之亦然
		2:open(fifo, O_RDONLY|O_NONBLOCK );  就不等待writer打开文件了
		3:open(fifo , O_WRONLY|O_NONBLOCK):
		 如果没有reader打开该管道文件的话,就直接报错,退出进程
		 用perror去抓信息,得到的会是No such device or address
		得先运行reader
	*/
	printf("opened ... \n");
	if(fd<0)
	{
		perror("Failed to open fifo:");
		return -1;
	}

	while(1)
	{
		int count;
		count=read(fd,buf,127);
		//要用底层io。read()会返回实际读到的字节数
		if(count>0)
		{
			buf[count]=0;//结束符,也可以='\0';
			printf("fifoReader receive a string:%s\n",buf);
		}
		if(strncmp(buf,"exit",4)==0)
		{
			break;
		}
	}
	close(fd);	
	return 0;
}

fifoWriter.c

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

#define FIFO "/root/c/process/ififo"
int main(void)
{
	int fd;
	char buf[128];

	if(mkfifo(FIFO, 0666))
	{
		perror("Mkfifo error");
	}
	printf("open for writing ... \n");
	// fd=open(FIFO,O_WRONLY);// 阻塞
	fd=open(FIFO,O_WRONLY|O_NONBLOCK);// 如果写端设置成非阻塞,不能先于读端运行,否则 open失败
	printf("opened... \n");
	if(fd<0)
	{
		perror("Failed to open fifo:");
		return -1;
	}
	
	while(1)
	{
		fgets(buf,128,stdin);//标准输入内容
		write(fd,buf,strlen(buf));//把缓存写入
		if(strncmp(buf,"exit",4)==0)
		{
			break;
		}
	}
	close(fd);
	unlink(FIFO);	
	return 0;
}

区别:

无名管道
1: 亲缘关系进程中
2:没有一个具体的文件 
3:调用write的时候必须保证有个fd[0]是没有closed 
4:pipe 在fork前 ( 申请管道并打开)
5:不保证写入数据的原子性


有名管道
1: 任意两个
2:具体文件
3: 调用write的时候必须保证有个读端(RDONLY的方式)是没有closed 
4:mkfifo  (申请)   
open(path, O_RDONLY)  阻塞, read 是阻塞的,会等有数据可读才返回
open(path,O_RDONLY | O_NONBLOCK) 不阻塞, read也不阻塞,没有数据返回是0
5:保证写入数据的原子性
6:有名管道文件不能在window中存在

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值