linux IPC 通信 study 一:管道

linux 进程通信机制:分为基于system V 和posix。

常用的通信方式分为:

(1) 管道pipe和命名管道fifo.

(2) 信号signal

(3) 信号量semphore

(4) 消息队列 msg queue

(5) 共享内存share memory

(6) 套接字socket

详解如下:

1.1. 匿名管道通信pipe,它把一个进程的输入和另外一个进程的输出连接起来,读进程从头部读出数据,写进程从尾部写入数据,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,传输遵循“先入先出”(FIFO)的规则。数据从一个管道中读出后,便会从管道中删除,其他读进程再也不会读到该数据,当管道为空时,读进程会被阻塞,当管道满时,写进程也会被阻塞掉。管道实际上就是个只存在于内存中的文件,对这个文件的操作要通过两个已经打开文件进行,它们分别代表管道的两端。管道是一种特殊的文件,它不属于某一种文件系统,而是一种独立的文件系统,有其自己的数据结构。

默认情况下,匿名管道pipe是半双工通信(posix允许实现支持全双工管道)。

pipe只能在具有公共祖先的两个进程之间使用。

当要读管道时,在进程中要就爱那个写管道关闭,同理要写管道时,在进程中也要将读管道关闭。常量PIPE_BUF规定了内核的管道缓冲区大小。

sample code:

  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <unistd.h>  
  4. #include <sys/types.h>  
  5. #include <errno.h>  
  6.   
  7. int main(int argc, char **argv)  
  8. {  
  9.         int ret = 0;  
  10.         int pipe_fd[2] = {0};  
  11.         char buf[128] = {0};  
  12.         char *p_write_buf;  
  13.         int num = 0;  
  14.         pid_t child_id;  
  15.   
  16.         if (pipe(pipe_fd) < 0 ) {  
  17.                 fprintf(stderr, "create pipe failed\n");  
  18.                 return -1;  
  19.         }  
  20.   
  21.         child_id = fork();  
  22.   
  23.         if (child_id < 0){  
  24.                 fprintf(stderr, "fork error\n");  
  25.         return -1;  
  26.         } else if(0 == child_id) {  /*child process*/  
  27.                 fprintf(stdout,"child process...\n");  
  28.                 close(pipe_fd[1]);  
  29.                 sleep(2);/*wait for father write pipe*/  
  30.                 num = read(pipe_fd[0], buf, 128);  
  31.                 if (num > 0)  
  32.                         fprintf(stdout, "child read:%s\n", buf);  
  33.                 close(pipe_fd[0]);  
  34.                 exit(0);  
  35.         } else {/*father process*/  
  36.                 fprintf(stdout, "father process..\n");  
  37.                 close(pipe_fd[0]);  
  38.                 ret = write(pipe_fd[1], "haha,", 5);  
  39.                 //ret = write(pipe_fd[1], "write first", 20);  
  40.         fprintf(stdout, "father write1 ret = %d\n", ret);  
  41.                 ret = write(pipe_fd[1], "pipe!", 5);  
  42.                 //ret = write(pipe_fd[1], "write second", 20);  
  43.         fprintf(stdout, "father write2 ret = %d\n", ret);  
  44.                 close(pipe_fd[1]);  
  45.                 sleep(3);  
  46.                 waitpid(child_id, NULL, 0);  
  47.                 exit(0);  
  48.         }  
  49.   
  50.   
  51.         return ret;  
  52. }  


1.2 命名管道FIFO:不同于匿名管道,FIFO有一个pathname与之相关联,以文件的形式存在于文件系统中,无论是否是父子进程,都可以通过访问FIFO。

sample code:


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

#define FIFO "./myfifo"

int main(int argc,char** argv)
{
	int ret = 0;
	char buf[128] = {0};
	int  fd;
	int  nbytes_read;
	int idx = 0;
	
	if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
		fprintf(stdout, "cannot create fifo \n");

	/*read as a file */
	fd = open(FIFO,O_RDONLY|O_NONBLOCK,0);
	if (fd == -1) {
		fprintf(stdout, "open failed");
		exit(1);	
	}

	while(1) {

		memset(buf,0,sizeof(buf));
		nbytes_read = read(fd, buf, 128);
		fprintf(stdout, "FIFO read %d times, len: %d  ", idx++, nbytes_read);
		if(nbytes_read == -1) {
			if(errno==EAGAIN)
				fprintf(stdout, "fifo empty\n");
		}
		fprintf(stdout, "context: %s \n", buf);
		sleep(1);
	}	
	pause();
	unlink(FIFO); 
	close(fd);

	return ret;
}


写fifo

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

#define FIFO "./myfifo"

main(int argc,char** argv)
{
	int ret = 0;
	int fd = 0;
	char buf[128] = {0};
	int nbytes_write = 0;
		
	fd = open(FIFO, O_WRONLY|O_NONBLOCK, 0);
	while (1) {

		fprintf(stdout, "pls input:\n");

		fgets(buf,128, stdin);
		
		nbytes_write = write(fd, buf, strlen(buf));
		printf("file write num = %d\n", nbytes_write);
		if(nbytes_write == -1) {
			if(errno==EAGAIN)
				fprintf(stdout, "The FIFO has not been read yet.\n");
		} else { 
			fprintf(stdout, "FIFO write: %s\n",buf);
		}
	}
	close(fd);

	return ret;
}


测试程序中有2 个问题:

(1)FIFO中的数据被读出来一次之后,程序不退出,再次读取就读不到任何内容了,写程序一直再写。

(2)FIFO中的内容被读走之后,FIFO buffer中的数据反而没有被清空,程序退出,再执行,还是能够读出同样的内容?

(3)当有多个写进程时,写进程必须全部启动起来,然后再启动读进程,工作正常,但是一旦读进程跑起来的之后,再启动加入的写进程写入的内容反而不能被读出来。如果只有一个读一个写,读写任意一个先启动都不会影响。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值