1. Timeout 개요
□ Timeout이란?
- 사전적으로, '프로그램이 특정한 시간 내에 성공적으로 수행되지 않아서 진행이 자동적으로 중단되는 것'
- 응답을 무한정 기다릴 수 없기 때문에 기다릴 시간을 정해야 함
□ Timeout 사용 사례
- Socket(양방향 통신), Http(단방향 통신)에서 다양하게 활용함
- JDBC
- JDBC Driver Type4는 소켓을 사용하여 DBMS에 연결하는 방식
- DB 커넥션 요청을 했으나, 특정 시간 내에 연결이 안될 때 → Connection Timeout 발생 - 채팅 프로그램
- 채팅 프로그램에서, 서버로부터 특정 시간 응답이 없을 때 → Socket Timeout 발생 - WEB
- 클라이언트에서 서버로 request를 날렸을 때, 연결이 되지 않은 상태로 특정시간 이상 대기 → Connection Timeout 발생
□ 관련 패키지
- java.net
- HttpClient
2. java.net 패키지
□ java.net 패키지 개요
- 네트워킹 응용 프로그램을 구현하기위한 클래스를 제공하는 패키지
- java.net 패키지는 크게 두 섹션으로 나눌 수 있음
- 저수준 API :
(1) Addresses, which are networking identifiers, like IP addresses.
(2) Sockets, which are basic bidirectional data communication mechanisms.
(3) Interfaces, which describe network interfaces.
- 고수준 API :
(1) URIs, which represent Universal Resource Identifiers.
(2) URLs, which represent Universal Resource Locators.
(3) Connections, which represents connections to the resource pointed to by URLs.
□ java.net 패키지에서 제공하는 4개의 socket
- Socket : TCP 클라이언트 API이며 일반적으로 원격 호스트에 연결 하는 데 사용됨
- ServerSocket : TCP 서버 API이며 일반적으로 클라이언트 소켓의 연결을 허용함
- DatagramSocket : UDP 엔드포인트 API이며 datagram 패킷을 주고 받는데 사용됨
- MulticastSocket : multicast 그룹을 처리하는 DatagramScoket의 하위클래스임
- TCP 소켓을 통한 송수신은 Socket.getInputStream() 메소드 및 Socket.getOutputStream()메소드 를 통해 얻을 수 있는 InputStreams 및 OutputStreams를 통해 수행됨
docs.oracle.com/javase/7/docs/api/java/net/package-summary.html
□ Socket 관련 Timeout
ㅇ Connection Timeout
ㅇ Socket Timeout / Read Timeout
□ Connection Timeout
- 정의
- 클라이언트가 서버측으로 Connection을 맺길 원하지만, 서버의 장애 상황으로 connection조차 맺어지지 못할 때 발생하는 timeout - Connection 과정
- TCP 소켓 통신에서 클라이언트와 서버가 연결(Connection)될 때 정확한 전송을 보장하기 위해 상대방 컴퓨터와 사전에 세션을 수립함. 이 과정을 3-Way handshake라고 함
- 3-way handshake가 정상적으로 끝나야 Connection이 됐다고 표현할 수 있음
- 즉, Connection Timeout이란 3-way HandShake가 정상적으로 수행되어 서버에 연결되기까지 소요된 시간임 - TCP 3-Way Handshake 절차
(1) A클라이언트는 B서버에 접속을 요청하는 SYN패킷을 보낸다. 이때 A클라이언트는 SYN 을 보내고 SYN/ACK 응답을 기다리는SYN_SENT 상태가 되는 것이다.
(2) B서버는 SYN요청을 받고 A클라이언트에게 요청을 수락한다는 ACK 와 SYN flag 가 설정된 패킷을 발송하고 A가 다시 ACK으로 응답하기를 기다린다. 이때 B서버는 SYN_RECEIVED 상태가 된다.
(3) A클라이언트는 B서버에게 ACK을 보내고 이후로부터는 연결이 이루어지고 데이터가 오가게 되는것이다. 이때의 B서버 상태가 ESTABLISHED 이다.
* SYN : synchronize sequence numbers
* ACK : acknowledgment
* 4-Way handshake: 3-Way handshake는 TCP의 연결을 초기화 할 때 사용한다면, 4-Way handshake는 세션을 종료하기 위해 수행되는 절차임
□ Socket Timeout
- 정의
- 클라이언트와 서버가 연결된 후에 서버는 데이터를 클라이언트에게 전송하게 됨. 이 때 하나의 데이터 덩어리가 아닌 여러개의 패킷으로 나눠서 전송하게 되는데, 각 패킷이 전송될 때 시간 차이(Gap)가 있음. 이 차이 시간의 제한(임계치)을 SocketTimeout 이라고 함 - read timeout과의 관계
- 클라이언트와 서버가 connection은 맺어졌지만 I/O작업이 길어지거나 락이 걸려 요청이 처리되지 못하고 있을 때 클라이언트는 더 이상 기다리지 못하고 커넥션을 끊음. 이런 상황을 Read Timeout 이라고 함. - java.net 에서는 socket timeout과 read timeout을 혼용하며, setSoTimeout() 메소드를 사용함
- document 참조 "setSoTimeout() : InputStream에서 데이터를 읽을 때의 Timeout 설정"
- timeout 시 SocketTimeout Exception 발생 : java.net.SocketTimeoutException: Read timed out"
예시코드
테스트
□ Connection, Socket/Read timeout과 관련된 예외
java.net.SocketException
: Thrown to indicate that there is an error creating or accessing a Socket. → connection timeout
java.net.SocketTimeoutException : Signals that a timeout has occurred on a socket read or accept. → socket timeout, read timeout
3. HttpClient 라이브러리
□ Apache HttpClient란
ㅇ 개요
- HTTP 프로토콜을 손쉽게 사용할 수 있게 해주는 클라이언트측 HTTP 전송 라이브러리
- Apache HttpComponents 제품군의 HttpClient는 http 통신을 위한 표준이 되어옴
- httpURLConnection의 단점(connection pooling)을 채우는 다양한 API를 가진 성숙한 프로젝트
(HttpClient from Apache HttpComponents suite has been a standard choice for http communication. It is a mature project, with rich API that fills many HttpURLConnection shortcomings e.g. connection pooling.)
ㅇ 사용 예시
- Apache HttpClient를 이용하면 간편하게 HTTP request를 보낼 수 있음. 간혹 웹 서버를 만들면서 다른 서버로 보터 request를 보내 response 받아 데이터를 처리해야 할 때가 있음. 이 때 HttpClient를 이용하면 간단하게 구현 가능함
ㅇ java.net 패키지와의 차이점
- java.net 패키지는 HTTP를 통해 리소스에 액세스 하기 위한 기본 기능을 제공하지만, 많은 애플리케이션에 필요한 완전한 유연성이나 기능을 제공하지 않음
- HttpClient 패키지는 최신 HTTP 표준 및 권장 사항의 클라이언트 측을 구현하는 효율적이고 최신이며 기능이 풍부한 패키지를 제공하여 이 공백을 채우려고 함
- 확장을 위해 설계된 HttpClient는 기본 HTTP 프로토콜에 대한 강력한 지원을 제공하는 동시에 웹 브라우저, 웹 서비스 클라이언트 또는 분산 통신을 위해 HTTP 프로토콜을 활용하거나 확장하는 시스템과 같은 HTTP 인식 클라이언트 응용 프로그램을 구축하는 모든 사람에게 유용 할 수 있음
□ HttpClient에서 제공하는 timeout 관련 메소드
ㅇ setConnectTimeout
- 서버와 연결을 맺을 때의 타임아웃
ㅇ setConnectionRequestTimeout
- ConnectionManager(커넥션풀)로부터 꺼내올 때의 타임아웃
ㅇ setSocketTimeout
- 요청/응답간의 타임아웃
* Connection Pooling
HttpClient로 빈번히 connection을 맺었다가, 사용이 끝나면 끊고 하다 보면 더 이상 connection을 열 수 없는 경우가 발생할 수 있다.
그 이유는 connection을 닫는다고 호출을 해도, 실제로는 어느 정도 TIME_WAIT 상태에 있다가 끊어지는데 이런 것들이 많이 쌓여 있으면 File Descriptor가 꽉 찼다는 에러(Too Many Open Files)가 나면서 connection을 맺지 못 하게 된다.
이런 현상을 방지하기 위해서는 Connection을 재사용할 수 있도록 HttpClient에서 제공하는 Connection Pool을 사용하는 것이다.
getHttpClient를 호출할 때 Connection Pool이 지정된 사이즈로 생성된다. 그리고, Connection을 하나 만들어 리턴한다.
Pool을 사용할 때마다 항상 주의할 것은 역시 반환을 꼭 해 줘야 한다는 것이다.
finally에선 항상 리소스를 반납한다. ==> ConnectionManager.release(response);
□ Timeout 예시
ㅇ HttpClient 4.3 이전(Configuring Timeouts Before HttpClient 4.3)
DefaultHttpClient httpClient = new DefaultHttpClient();
int timeout = 5; // seconds
HttpParams httpParams = httpClient.getParams();
httpParams.setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, timeout * 1000);
httpParams.setParameter(
CoreConnectionPNames.SO_TIMEOUT, timeout * 1000);
httpParams.setParameter(
ClientPNames.CONN_MANAGER_TIMEOUT, new Long(timeout * 1000));
ㅇ HttpClient 4.3(Configure Timeouts Using the New 4.3. Builde)
int timeout = 5;
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000)
.setSocketTimeout(timeout * 1000).build();
CloseableHttpClient client =
HttpClientBuilder.create().setDefaultRequestConfig(config).build();
ㅇ 기타 참조
HttpClient httpclient = new DefaultHttpClient();
int useTimeout = 3;
//HttpClient timeout 셋팅
if(useTimeout>0){
httpclient.getParams().setParameter("http.protocol.expect-continue", false);//HttpClient POST 요청시 Expect 헤더정보 사용 x
httpclient.getParams().setParameter("http.connection.timeout", useTimeout * 1000);// 원격 호스트와 연결을 설정하는 시간
httpclient.getParams().setParameter("http.socket.timeout", useTimeout * 1000);//데이터를 기다리는 시간
httpclient.getParams().setParameter("http.connection-manager.timeout", useTimeout * 1000);// 연결 및 소켓 시간 초과
httpclient.getParams().setParameter("http.protocol.head-body-timeout", useTimeout * 1000);
}
ㅇ 기타 참조
// There are 3 timeouts settings available:
val requestConfig = RequestConfig.custom()
// Determines the timeout in milliseconds until a connection is established.
.setConnectTimeout(5_000)
// Defines the socket timeout in milliseconds,
// which is the timeout for waiting for data or, put differently,
// a maximum period inactivity between two consecutive data packets).
.setSocketTimeout(5_000)
// Returns the timeout in milliseconds used when requesting a connection
// from the connection manager.
.setConnectionRequestTimeout(2_000)
.build()
// 10초로 설정한 예제
HttpPost request = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(10*1000)
.setConnectTimeout(10*1000)
.setConnectionRequestTimeout(10*1000)
.build();
request.setConfig(requestConfig);
'네트워크' 카테고리의 다른 글
[네트워크] 소켓 프로그래밍이란(Socket Programming) (0) | 2020.12.21 |
---|