我正在尝试使用流程构建器类从java运行用C编写的交互式程序。 C程序非常简单,它要求用户输入一个数字并输出相同的数字给用户。 当我试图运行java程序时它会挂起,请让我知道这个问题。
Java程序
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package testapp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author pradeep
*/
public class TestApp {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException, InterruptedException {
Process process = new ProcessBuilder("/home/pradeep/a.out").start();
final InputStream in = process.getInputStream();
final OutputStream out = process.getOutputStream();
final BufferedReader br = new BufferedReader(new InputStreamReader(in));
//Thread.currentThread().sleep(5000);
new Thread(new Runnable() {
@Override
public void run() {
try {
int ch;
String line;
System.out.println("Read started");
do {
//line=br.readLine();
ch = in.read();
System.out.print((char)ch);
}while(ch!=-1);
System.out.println("Read ended");
} catch (IOException ex) {
Logger.getLogger(TestApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
int i=0;
System.out.println("write started");
out.write(((i++)+"\n").getBytes());
System.out.println("write completed");
} catch (IOException ex) {
Logger.getLogger(TestApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
int result = process.waitFor();
//out.close();
//in.close();
System.out.println("result:"+result);
}
}
C程序
#include<stdio.h>
int main() {
int number;
int i=10;
printf("Enter number:\n"); scanf("%d",&number); printf("Entered
number:%d\n",number);
return 0;
}
当我在java程序中修改写线程时,如下所示,我得到了输出。
new Thread(new Runnable() {
@Override
public void run() {
try {
int i=0;
System.out.println("write started");
while(i<2000) {
//System.out.println("W->"+i);
out.write(((i++)+"\n").getBytes());
}
System.out.println("write completed");
} catch (IOException ex) {
Logger.getLogger(TestApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();
以下是框架代码
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.amphisoft.framework;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author pradeep
*/
public class ProcessManager {
private static ArrayBlockingQueue<Task> taskQueue = new ArrayBlockingQueue<Task>(10);
private static Map<Integer,ProcessHolder> processMap = new HashMap<Integer,ProcessHolder>();
private static ProcessManager instance;
Integer id = 0;
Log log = LogFactory.getLog(ProcessManager.class);
private ProcessManager() {
new Thread() {
@Override
public void run() {
try {
Task task;
while((task = taskQueue.take()) != null) {
Process process = task.processBuilder.start();
ProcessHolder processHolder = new ProcessHolder(process,process.getInputStream(),process.getOutputStream());
if(task.hasInput) {
WriteThread writeThread = new WriteThread(processHolder);
writeThread.start();
}
if(task.hasOutput) {
ReadThread readThread = new ReadThread(processHolder);
readThread.start();
}
processMap.put(task.id,processHolder);
System.out.println("waiting for process");
process.waitFor();
System.out.println("process completed");
}
}catch(Exception e) {
e.printStackTrace();
}
}
}.start();
}
public static ProcessManager getInstance() {
if(instance == null) {
instance = new ProcessManager();
}
return instance;
}
public Integer addTask(Task task) {
id++;
task.id = id;
taskQueue.add(task);
return task.id;
}
public ProcessHolder getProcessHolder(Integer id) {
log.info("Get ProcessHolder:"+id);
log.info("Process Map:"+processMap);
return processMap.get(id);
}
}
ProcessHolder.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.amphisoft.framework;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PipedReader;
import java.io.PipedWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author pradeep
*/
public class ProcessHolder {
private Process process;
private PipedReader reader;
private PipedWriter readerInput;
private PipedWriter writer;
private PipedReader writerOutput;
private BufferedReader in;
private BufferedWriter out;
Log log = LogFactory.getLog(ProcessHolder.class);
public ProcessHolder(Process process, InputStream in, OutputStream out) throws IOException {
this.process = process;
this.in = new BufferedReader(new InputStreamReader(in));
this.out = new BufferedWriter(new OutputStreamWriter(out));
readerInput = new PipedWriter();
reader = new PipedReader(readerInput);
writer = new PipedWriter();
writerOutput = new PipedReader(writer);
}
public void readToPipe() throws IOException, InterruptedException {
String line = "";
log.info("Inside readToPipe");
int ch;
while((ch = in.read()) != -1) {
log.info(ch);
readerInput.write(ch);
readerInput.flush();
}
log.info("Closing the read Pipe");
in.close();
readerInput.close();
}
public void writeFromPipe() throws IOException, InterruptedException {
char[] buffer = new char[512];
int ch;
log.info("Inside writeFromPipe to write");
while((ch = writerOutput.read()) != -1) {
log.info(ch);
out.write(ch);
out.flush();
}
log.info("Closing the write Pipe");
out.close();
writerOutput.close();
}
public PipedReader getReader() {
return reader;
}
public PipedWriter getWriter() {
return writer;
}
}
Task.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.amphisoft.framework;
/**
*
* @author pradeep
*/
public class Task {
public ProcessBuilder processBuilder;
public Integer id;
public boolean hasInput;
public boolean hasOutput;
}
WriteThread.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.amphisoft.framework;
/**
*
* @author pradeep
*/
public class WriteThread extends Thread{
ProcessHolder processHolder;
public WriteThread(ProcessHolder processHolder) {
this.processHolder = processHolder;
}
public void run() {
try {
processHolder.writeFromPipe();
}catch(Exception e) {
e.printStackTrace();
}
}
}
ReadThread.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.amphisoft.framework;
/**
*
* @author pradeep
*/
public class ReadThread extends Thread{
public ProcessHolder processHolder;
public ReadThread(ProcessHolder processHolder) {
this.processHolder = processHolder;
}
public void run() {
try {
processHolder.readToPipe();
}catch(Exception e) {
e.printStackTrace();
}
}
}
应用程序使用processmanager类将进程添加到队列,它负责运行进程并启动读写线程。
答案 0 :(得分:2)
问题是进程的输入和输出流是缓冲的。
当您向流程写入一行时,单行不足以填充缓冲区。输出流在将全部写入进程之前等待更多数据填充缓冲区。在您的第一个示例中,您的Java程序正在挂起,因为C程序正在等待从Java程序发送的输入行,但是由于缓冲,这种情况永远不会发生。
解决方案是flush输出流。刷新输出流将当前保存在缓冲区中的任何数据发送到目标。要刷新输出流,请添加行
out.flush();
在第一个示例中的out.write
行之后。
在第二个示例中,您将大量数字写入输出流。这显然足以填充缓冲区并使输出流将数据发送到C程序。
答案 1 :(得分:1)
由于您在第一个代码示例中只写了一个数字(没有while循环,只写“0 \ n”),您可以flush或关闭输出流。