티스토리 뷰

자바의 InputStream과 OutputStream은 외부와의 I/O를 위한 인터페이스를 제공한다.

이번에 다룰 주제인 InputStream은 I/O 중 I에 대한 부분을 다룬다.

 

대표적인 3가지 사용처는 콘솔과의 표준 입출력, 파일 입출력, 소켓과의 입출력이다.

 

오늘 다룰 내용은 자바 ee 어플리케이션에서의 inputstream이다.

 

자바 ee 서버에서는 HttpServletRequest가 존재하고,

이 클래스를 통해 inputstream을 가져올 수 있게 되어 있다. 

그렇기 때문에, request.getInputStream(); 과 같은 형태로 서블릿 내에서 inputstream을 받아와 사용할 수 있는 것이다.

톰캣에서는 CoyoteInputStream이란 이름으로 단일한 형태의 inputstream을 제공하고,

제우스의 경우에는 요청의 종류에 따라 WjpInputStream, Ajp13InputStream, ServletInputStreamImpl을 제공한다.

 

오늘 다룰 내용은 inputstream 사용 시에 주의할 점에 대한 내용이다.

 

다시 한번 말하지만, inputstream은 외부와 통신하기 위한 인터페이스이다.

자바는 C언어와 다르다.

OS의 민감한 부분에 직접적으로 접근하는 부분은 jdk에서 제공한 수단으로만 접근할 수 있다는 점에 유의한다.

 

inputstream은 기본적으로 socket에서 가져온 inputstream을 사용한다.

그리고, read 메서드를 호출하면, 인자에 따라 1byte를 읽거나, 정해진 양만큼 읽어오려고 시도한다.

어플리케이션에서 요구한 양보다 버퍼에 있는 양이 더 적으면, 그냥 적은걸 던져준다.

-1을 리턴하는 경우는 연결이 끊겼을 때이고, 단순히 읽을 것이 없는 경우엔 0을 던저주는 것이 아니라, blocking 된다.

 

따라서 만약에 어플리케이션이 구현이 잘못되었다면, 

 

1. read 메서드에 의해 blocking이 될 수 있다.

2. 읽어오고자 하는 데이터를 전부다 읽어오지 못할 수도 있다. 

 

위와 같은 위험성을 제거하기 위해, inputstream은 available 메서드를 제공한다. 

available 메서드는 지금 읽어올 수 있는 데이터의 양을 제공해주는 메서드이다.

이 메서드의 이름만 봐서는 현재 읽을 수 있는 값을 정확하게 돌려줄 수 있을 것 같다.

그러나 결코 그렇지 않기 때문에 사용에 많은 주의가 필요하다.

 

엄밀히 말하면, 이 메서드는 "현재 확실히 읽을 수 있는 버퍼의 크기"를 제공한다.

java doc에 가보면, "estimated value"를 제공한다고 되어 있다.

이는 이 메서드가 call 되는 시점과, 버퍼가 차오르는 시점이 다를수 있기 때문이다.

available 메서드로 얼마나 읽을 수 있을지 확인하고 있는 그 시점에도, 

새로운 데이터는 버퍼에 계속 쌓이고 있기 때문이다. 

 

이 때문에, available 메서드가 의도한대로 동작하지 않는 경우도 존재한다.

예를 들어, available이 0일 때, 루프를 탈출하도록 작성했다고 가정한다.

 

InputStream is = socket.inputStream();

while(is.available()>0) {}

클라이언트에서 데이터를 보내도, 해당 루프를 아예 돌지 않을 수 있다는 것이다.

왜냐하면, is.available을 호출하는 시점에는 클라이언트에서 보낸 데이터가 도착하지 않았지만,

그 이후엔 계속 클라이언트에서 보낸 데이터가 버퍼에 쌓일 수 있다. 

 

자바 ee 서버에서는 inputstream 구현체를 만들면서(tomcat의 경우 CoyoteInputStream),

해당 메서드도 오버라이드 해버리는 경우도 있어 위 설명과 동작이 다를 수도 있다.

어찌되었든 그로 인해 다른 문제가 생길수도 있기 때문에 문서를 보거나 구현을 확인한 후에 사용하도록 하자.

 

결론은 아래와 같다.

 

자바 어플리케이션 내에서 inputstream으로 값을 읽어올 때에는, 위의 상황을 고려하지 않으면,

데이터를 끝까지 읽지 못하거나, blocking이 될 위험성이 있다. 

그렇기 때문에 자바 어플리케이션 내에서 inputstream으로 값을 읽어올 때에는 주의가 필요하다.

 

특히 tomcat의 AJP 프로토콜은 read 메서드로 한번에 8186바이트만 읽을 수 있기 때문에,

그거보다 큰 데이터를 읽어오는 경우엔 별도의 처리를 해주는게 맞아보인다.

 

참고로 request#getParameter() 메서드로 호출할 때에는, http header에 포함된 content-length 만큼 데이터를 읽어

맵을 만들도록 구현하기 때문에, 이 문제에 대해 고려할 필요가 없다.

'개발 > 아파치와 톰캣' 카테고리의 다른 글

Tomcat HTTP location Header 이슈  (1) 2019.08.18
ajp 요청 헤더2  (0) 2019.01.20
AJP 요청 헤더  (0) 2018.10.27
ajp 프로토콜 설정  (0) 2018.07.08
아파치 간단 빌드  (0) 2018.07.06
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함