Process.getInputStream()차단 문제 해결
16003 단어 ProcessgetInputStream가로막다
자바
Runtime.getInstance().exec (String cmd)
혹은
new ProcessBuilder(String cmd).start()
하위 프로 세 스 대상 Process 를 만 들 수 있 습 니 다.process 대상 을 호출 하 는 waitFor()방법 을 통 해 메 인 프로 세 스 를 대기 상태 로 들 어가 하위 프로 세 스 가 실 행 될 때 까지 다음 작업 을 진행 할 수 있 습 니 다.하위 프로 세 스 를 잘못 처리 하면 메 인 프로 세 스 가 막 혀 프로그램 전체 가 죽 을 수 있 습 니 다.자바 Api 에서 Process 에 대해 말 하 는 것 은:
ProcessBuilder.start()와 Runtime.exec 방법 으로 이 컴퓨터 프로 세 스 를 만 들 고 Process 하위 클래스 의 인 스 턴 스 를 되 돌려 줍 니 다.이 인 스 턴 스 는 프로 세 스 를 제어 하고 관련 정 보 를 얻 을 수 있 습 니 다.프로 세 스 클래스 는 프로 세 스 입력,출력 실행,프로 세 스 완료 대기,프로 세 스 종료 상태 검사,프로 세 스 를 없 애 는 방법 을 제공 합 니 다.
프로 세 스 를 만 드 는 방법 은 이 컴퓨터 플랫폼 의 특정 프로 세 스 를 잘 작 동 하지 못 할 수도 있 습 니 다.예 를 들 어 이 컴퓨터 창 프로 세 스,데 몬,Microsoft Windows 의 Win 16/DOS 프로 세 스,셸 스 크 립 트 등 입 니 다.만 든 하위 프로 세 스 는 터미널 이나 콘 솔 이 없습니다.모든 표준 io(즉 stdin,stdout,stderr)작업 은 세 개의 흐름(getOutputStream(),getInputStream(),getErrorStream()을 통 해 부모 프로 세 스 로 재 설정 합 니 다.부모 프로 세 스 는 이 흐름 을 사용 하여 하위 프로 세 스 의 입력 과 하위 프로 세 스에 서 출력 을 가 져 옵 니 다.일부 이 플랫폼 은 표준 입력 과 출력 흐름 에 만 제 한 된 버퍼 크기 를 제공 하기 때문에 읽 기 쓰기 서브 프로 세 스 의 출력 흐름 이나 입력 흐름 이 신속하게 실패 하면 서브 프로 세 스 가 막 히 고 심지어 잠 금 이 생 길 수 있 습 니 다.
getOutputStream(),getInputStream(),getErrorStream()에 대한 설명 에서 주의사항 이 있 습 니 다.출력 흐름 과 오류 흐름 을 버퍼 링 하 는 것 은 좋 은 생각 입 니 다!응,추상 적 이 야!
문 제 는 바로 여기에 있 습 니 다.Process.getInputStream()과 Process.getErrorStream()은 각각 Process 의 표준 출력 흐름 과 오류 흐름 을 되 돌려 줍 니 다.두 흐름 이 잘못 처리 되면 버퍼 가 제때에 제거 되 지 않 고 가득 차 면 프로 세 스 가 막 힙 니 다.Process.destory()를 호출 하 더 라 도 막 힌 하위 프로 세 스 를 없 앨 수 있 는 것 은 아 닙 니 다.
Process 의 출력 흐름 과 오류 흐름 을 동기 화하 여 처리 하려 고 시도 하면 반드시 효과 가 있 는 것 은 아 닙 니 다.순서 실행 과정 에서 출력 흐름 과 오류 흐름 은 제때에 처리 되 지 못 합 니 다.해결 방안 은 두 가지 가 있다.
프로젝트 1:process 의 출력 흐름 과 오류 흐름 을 동시에 가 져 옵 니 다.
두 스 레 드 를 시작 하여 출력 흐름 과 오류 흐름 을 동시에 읽 고 처리 합 니 다.IDE 를 열기 가 귀 찮 습 니 다.코드 를 대충 두 드 려 보 세 요.오류 가 있 을 수 있 습 니 다.다음 과 같 습 니 다.
호출 자:
class ProcessExecutor
{
private Process p;
private List<String> outputList;
private List<String> errorOutputList;
public ProcessExecutor(Process p) throws IOException
{
if(null == p)
{
throw new IOException("the provided Process is null");
}
this. p = p;
}
public List<String> getOutputList()
{
return this. outputList;
}
public List<String> getErrorOutputList()
{
return this.errorOutputList;
}
public int execute()
{
int rs = 0;
Thread outputThread = new ProcessOutputThread(this.p.getInputStream());
Thread errorOutputThread = new ProcessOutputThread(this.p.getErrorStream());
outputThread.start();
errorOutputThread.start();
rs = p.waitFor();
outputThread.join();
errorOutputThread.join();
this.outputList = outputThread.getOutputList();
this.errorOutputList = errorOutputThread.getOutputList();
return rs;
}
}
흐름 처리 스 레 드
class ProcessOutputThread extends Thread
{
private InputStream is;
private List<String> outputList;
public ProcessOutputThread(InputStream is) throws IOException
{
if(null == is)
{
throw new IOException("the provided InputStream is null");
}
this. is = is;
this.outputList = new ArrayList<String>();
}
public List<String> getOutputList()
{
return this. outputList;
}
@Override
public void run()
{
InputStreamReader ir = null;
BufferedReader br = null;
try
{
ir = new InputStreamReader(this.is);
br = new BufferedReader(ir);
String output = null;
while(null != (output = br.readLine()))
{
print(output);
this.outputList.add(output);
}
}
catch(IOException e)
{
e.print();
}
finally
(
try
{
if(null != br)
{
br.close();
}
if(null != ir)
{
ir.close();
}
if(null != this.is)
{
this.is.close();
}
}
catch(IOException e)
{
e.print();
}
)
}
}
프로젝트 2:ProcessBuilder 의 redirect ErrorStream()방법 으로 출력 흐름 과 오류 흐름 을 통합 합 니 다.
public int execute()
{
int rs = 0;
String[] cmds = {...};//command and arg
ProcessBuilder builder = new ProcessBuilder(cmds);
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output = null;
while (null != (readLine = br.readLine()))
{
print(output);
}
rs = process.waitFor();
return rs;
}
자바 프로 세 스 블록 테스트 총화Process 차단 원인:입력 흐름 과 오류 흐름 이 분리 되 고 처리 하지 않 으 면 차단 이 발생 합 니 다.결국은 본질 적 으로 bio 가 야기 하 는 io 차단 문제 입 니 다.
getInputStream,getErroSteam 은 스 크 립 트 나 명령 을 가 져 오 는 콘 솔 리 턴 정보 입 니 다.전 자 는 표준 출력 리 턴 정 보 를 얻 었 고 후 자 는 표준 오류 리 턴 정 보 를 얻 었 습 니 다.
Process 원리:Runtime.getRuntime().exec(cmd)를 사용 하면 현재 프로 세 스에 하위 프로 세 스 를 만 듭 니 다.하위 프로 세 스 는 콘 솔 이 없 기 때문에 표준 출력 과 표준 오류 가 부모 프로 세 스에 되 돌아 오기 때문에 getInputStream 과 getErrorStream 을 통 해 이 정 보 를 얻 을 수 있 습 니 다.
테스트 코드 는 다음 과 같 습 니 다:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class JavaExeBat {
public JavaExeBat() {
}
public static void main(String[] args) {
Process p;
//test.bat ipconfig/all
String cmd="sh test.sh ";
//String cmd="ping 127.0.0.1 -c 4";
try {
//
p = Runtime.getRuntime().exec(cmd);
//
//
InputStream fis=p.getInputStream();
//
InputStream ferrs=p.getErrorStream();
//
InputStreamReader isr=new InputStreamReader(fis);
InputStreamReader errsr=new InputStreamReader(ferrs);
//
BufferedReader br=new BufferedReader(isr);
BufferedReader errbr=new BufferedReader(errsr);
String line=null;
String lineerr = null;
//
while((line=br.readLine())!=null) {
//
System.out.println("return input Str:" + line);
}
while((lineerr=errbr.readLine())!=null){
//
System.out.println("return err Str:" + lineerr);
}
int exitVal = p.waitFor();
System.out.println("exitVal:" + exitVal);
} catch (Exception e) {
e.printStackTrace();
}
}
}
test.sh 아래
#!/bin/bash
for((i=0; i < 100000; i++));do
//
echo "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
//
echo "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 1>&2
done
테스트 를 통 해 자바 Exebat.자바 파일 에서 표준 출력 이나 표준 오류 만 열 면 프로 세 스 가 다 져 져 서 waiteFor 를 통 해 반환 값 을 얻 을 수 없습니다.스 크 립 트 에서 각각 100000 w 개의 정 보 를 표준 출력 과 표준 오류 로 출력 했 기 때 문 입 니 다.다음 코드 는 getInputStream 만 처리 하여 표준 오류 출력 흐름 의 정 보 를 현재 프로 세 스에 너무 많이 되 돌려 줍 니 다.처리 되 지 않 아 막 혔 다.코드 는 다음 과 같 습 니 다:
p = Runtime.getRuntime().exec(cmd);
//
//
InputStream fis=p.getInputStream();
//
InputStreamReader isr=new InputStreamReader(fis);
//
BufferedReader br=new BufferedReader(isr);
String line=null;
//
while((line=br.readLine())!=null) {
//
System.out.println("return input Str:" + line);
}
int exitVal = p.waitFor();
System.out.println("exitVal:" + exitVal);
상기 코드 중의 getInputStream 을 getErrorStream 으로 바 꾸 면 프로 세 스 를 다 질 수 있 습 니 다.똑 같이 둘 중 하나,즉 표준 오류 만 처 리 했 기 때 문 입 니 다.그렇다면 두 개의 흐름 정 보 를 동시에 처리 할 수 있 을 까?코드 는 다음 과 같 습 니 다:
try {
//
p = Runtime.getRuntime().exec(cmd);
//
//
InputStream fis=p.getInputStream();
//
InputStream ferrs=p.getErrorStream();
//
InputStreamReader isr=new InputStreamReader(fis);
InputStreamReader errsr=new InputStreamReader(ferrs);
//
BufferedReader br=new BufferedReader(isr);
BufferedReader errbr=new BufferedReader(errsr);
String line=null;
String lineerr = null;
//
while((line=br.readLine())!=null) {
//
System.out.println("return input Str:" + line);
}
while((lineerr=errbr.readLine())!=null){
//
System.out.println("return err Str:" + lineerr);
}
int exitVal = p.waitFor();
System.out.println("exitVal:" + exitVal);
} catch (Exception e) {
e.printStackTrace();
}
}
테스트 후에 발견 해도 안 됩 니 다.동기 화 되 기 때문에 선후 순서 도 있 고 차단 도 발생 합 니 다.테스트 방법 은 test.sh 를 표준 오류 만 인쇄 하 는 것 으로 바 꾸 면 표준 오류 처리 가 막 히 는 것 을 발견 할 수 있 습 니 다.스 크 립 트 는 다음 과 같 습 니 다.
#!/bin/bash
for((i=0; i < 100000; i++));do
//
echo "testaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 1>&2
done
해결 방법:(1)두 개의 흐름 정 보 를 동시에 처리 하고 두 개의 스 레 드 를 열 어 각각 출력 흐름 과 오류 흐름 을 처리 합 니 다.
(2)두 개의 흐름 을 하나의 흐름 으로 합 쳐 해결 하 는 예:
첫 번 째 사고방식:
class ProcessExecutor
{
private Process p;
private List<String> outputList;
private List<String> errorOutputList;
public ProcessExecutor(Process p) throws IOException
{
if(null == p)
{
throw new IOException("the provided Process is null");
}
this. p = p;
}
public List<String> getOutputList()
{
return this. outputList;
}
public List<String> getErrorOutputList()
{
return this.errorOutputList;
}
public int execute()
{
int rs = 0;
Thread outputThread = new ProcessOutputThread(this.p.getInputStream());
Thread errorOutputThread = new ProcessOutputThread(this.p.getErrorStream());
outputThread.start();
errorOutputThread.start();
rs = p.waitFor();
outputThread.join();
errorOutputThread.join();
this.outputList = outputThread.getOutputList();
this.errorOutputList = errorOutputThread.getOutputList();
return rs;
}
}
class ProcessOutputThread extends Thread
{
private InputStream is;
private List<String> outputList;
public ProcessOutputThread(InputStream is) throws IOException
{
if(null == is)
{
throw new IOException("the provided InputStream is null");
}
this. is = is;
this.outputList = new ArrayList<String>();
}
public List<String> getOutputList()
{
return this. outputList;
}
@Override
public void run()
{
InputStreamReader ir = null;
BufferedReader br = null;
try
{
ir = new InputStreamReader(this.is);
br = new BufferedReader(ir);
String output = null;
while(null != (output = br.readLine()))
{
print(output);
this.outputList.add(output);
}
}
catch(IOException e)
{
e.print();
}
finally
(
try
{
if(null != br)
{
br.close();
}
if(null != ir)
{
ir.close();
}
if(null != this.is)
{
this.is.close();
}
}
catch(IOException e)
{
e.print();
}
)
}
}
두 번 째 사고방식:ProcessBuilder 를 사용 하여 ErrorStream(true)을 리 디 렉 션 합 니 다.출력 흐름 과 오류 흐름 을 합 칩 니 다.
public int execute()
{
int rs = 0;
String[] cmds = {...};//command and arg
ProcessBuilder builder = new ProcessBuilder(cmds);
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output = null;
while (null != (readLine = br.readLine()))
{
print(output);
}
rs = process.waitFor();
return rs;
}
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Python Process 생성 프로세스의 2가지 방법 상세 정보앞에서 os 사용을 소개했습니다.fork() 함수는 다중 프로세스 프로그래밍을 실현하는데 이 방법의 가장 뚜렷한 결함은 Windows 시스템에 적용되지 않는다는 것이다.이 섹션에서는 Python이 Windows 플랫...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.