Java使用管道实现进程间通讯

转载请注明出处:http://blog.csdn.net/jmppok/article/details/17500739

1.进程通讯

大家都知道进程间通讯有三种常用方式: 

1)管道

2)共享内存

3)socket

baidu也有说8种方式的,其实基本都是这三种方式的进一步细化。


2.Java进程通讯

Java没有共享内存机制,同时Java的管道也只能用于Java线程间的通讯。

下面是一个关于Java的管道简单的介绍:

Java提供管道功能,实现管道通信的类有两组:PipedInputStream和PipedOutputStream或者是PipedReader和PipedWriter。管道通信主要用于不同线程间的通信。

一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进行连接而产生一个通信管道。PipedOutputStream向管道中写入数据,PipedIntputStream读取PipedOutputStream向管道中写入的数据。一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据。

看来Java只能通过Socket实现进程间通讯了。Socket本身确实具有很好的通用性,而且可以跨主机通讯。但是Scoket本身也有一些弱点,如效率相对其他方式较低,开发成本较高等。最重要的是,这篇文章我们要介绍的是Java如何使用PIPE实现进程间通讯。所以只好委屈一下Socket了。

3.Java通过管道实现进程通讯

3.1管道的本质

首先,我们需要说明一个基本概念:什么是管道? 

管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建。


Linux管道的实现机制

从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:·
1)限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不象文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
2)读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题
注意:
从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛 弃,释放空间以便写更多的数据。

管道的结构
在Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。

过将两个file 结构指向同一个临时的VFS 索引节点,而这个VFS引节点又指向一个物理页面而实现的。

3.2 Java如何使用管道通讯

上面说到,管道实际上就是一个file结构和一个VFS的索引。也就是说管道是一个虚拟的文件。那在Java中是不是就可以通过直接读写这个文件,从而实现PIPE通讯的效果呢?

答案当然是肯定的。其步骤如下:

1)首先要创建一个管道文件,这一点Java 做不到,我们要借助C/C++中的mkfifo()函数来实现。

以下代码创建并打开两个管道,一个用于读取输入,一个用于输出:

  1. char name1[1024];  
  2. char name2[1024];  
  3. sprintf(name1,"./process_in");  
  4. sprintf(name2,"./process_out");  
  5. if(mkfifo(name1,0666 )<0)  
  6. {  
  7.  printf("\n error when mkfifo");      
  8. }  
  9. if(mkfifo(name2,0666 )<0)  
  10. {  
  11.  printf("\n error when mkfifo");      
  12. }  
  13.   
  14.   
  15. int fd1, fd2;  
  16. if ((fd1 = open (name1, O_RDWR ))<0)  
  17.     {  
  18.         perror("Could not open named pipe.");  
  19.     }  
  20. if ((fd2 = open (name2, O_RDWR ))<0)  
  21.     {  
  22.         perror("Could not open named pipe.");  
  23.     }  

这是查看当前目录,可以看到两个Pipe文件,它和普通文件不同,具有p属性,表明是一个管道文件。

2)Java中,使用文件读写的方式打开这两个文件,即可进行读写。

[java] view plain copy
  1. String namedPipe1=workdir+"/process_in";  
  2. String namedPipe2=workdir+"/process_out";  
  3.   
  4. File pipe1 = new File(namedPipe1);  
  5. File pipe2 = new File(namedPipe2);  
  6.   
  7. BufferedReader reader = new BufferedReader(new FileReader(pipe2));  
  8. //DataInputStream reader = new DataInputStream(new FileInputStream(pipe2));  
  9. BufferedWriter writer = new BufferedWriter(new FileWriter(pipe1));  
  10.   
  11. writer.write("test");  
  12.   
  13.          char [] buf = new char[8];  
  14. reader.read(buf);  



 3)需要注意的问题

  1)Java最好用单独的线程来读数据;

  2)Java写完数据后,需要flush();

展开阅读全文

没有更多推荐了,返回首页