달력

01

« 2018/01 »

  •  
  • 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
  •  
  •  
  •  
.. .. ..

 

B3 자바기반 Vert.x로 Socket.io 서버 만들기

http://devon.daum.net/2012/session/b3

.
Posted by .07274.

댓글을 달아 주세요

.. .. ..

.

 

%A 각국의 표현으로 완전한 요일명으로 옮겨놓을 수 있습니다.
%a 각국의 표현으로 생략 한 요일명으로 옮겨놓을 수 있습니다. 여기서, 약칭은 최초의 3 캐릭터입니다.
%B 각국의 표현으로 완전한 월명으로 옮겨놓을 수 있습니다.
%b 각국의 표현으로 생략 한 월명으로 옮겨놓을 수 있습니다. 여기서, 약칭은 최초의 3 캐릭터입니다.
%C (서기연 / 100)의 10 진수로 옮겨놓을 수 있습니다. 1 자리수의 숫자의 전에는 0 이 붙습니다.
%c 각국의 표현으로 시각과 일자로 옮겨놓을 수 있습니다 서식은 ctime(3) 하지만 생성하는 것과 같고,"%a %Ef %T %Y" 과 등가입니다. 이것은 또,"3+1+6+1+8+1+4" 의 출력 포맷을 의미합니다.
%D "%m/%d/%y" (와)과 동등합니다.
%d 날을 나타내는 10 진수 (01-31)로 옮겨놓을 수 있습니다.
%E* %O* POSIX 의 지역 확장입니다. %Ec %EC %Ex %EX %Ey %EY %Od %Oe %OH %OI %Om %OM %OS %Ou %OU %OV %Ow %OW %Oy 그렇다고 하는 순차 순서는, 대체적인 표현을 주는 것이라고 보여집니다.

더욱, %Ef 는 단축형의 달의 이름과 날을 나타내, 또 %EF 는 긴 형식의 달과 날을 나타내, 또 %OB 는 다른 형식의 달의 이름을 나타냅니다 (단독으로 사용해 일자는 지정하지 않습니다).

%e 날을 나타내는 10 진수 (1-31)로 옮겨놓을 수 있습니다. 1 자리수의 숫자의 전에는 공백이 붙습니다.
%G 백년기첨부의 해의 10 진수로 옮겨놓을 수 있습니다. 이 해는, 주의 대부분을 포함한 것이 됩니다 (월요일을 주의 최초일로서).
%g "" (와)과 같은 나이입니다만, 백년기없음의 10 진수 (00-99)로 옮겨놓을 수 있습니다.
%H (24 시간 시계로) 시간을 나타내는 10 진수 (00-23)로 옮겨놓을 수 있습니다.
%h %b 과 같습니다.
%I (12 시간 시계로) 시간을 나타내는 10 진수 (01-12)로 옮겨놓을 수 있습니다.
%j 1 년일을 나타내는 10 진수 (001-366)로 옮겨놓을 수 있습니다.
%k (24 시간 시계로) 시간을 나타내는 10 진수 (0-23)로 옮겨놓을 수 있습니다. 1 자리수의 숫자의 전에는 공백이 붙습니다.
%l (12 시간 시계로) 시간을 나타내는 10 진수 (1-12)로 옮겨놓을 수 있습니다. 1 자리수의 숫자의 전에는 공백이 붙습니다.
%M 분을 나타내는 10 진수 (00-59)로 옮겨놓을 수 있습니다.
%m 달을 나타내는 10 진수 (01-12)로 옮겨놓을 수 있습니다.
%n 개행으로 옮겨놓을 수 있습니다.
%O* %E* 과 같습니다.
%p 각국의 표현으로 "오전" 또는 "오후" 의 어느쪽이든 해당하는 표시로 옮겨놓을 수 있습니다.
%R "%H:%M" (와)과 동등합니다.
%r "%I:%M:%S %p" (와)과 동등합니다.
%S 초를 나타내는 10 진수 (00-60)로 옮겨놓을 수 있습니다.
%s 세계 표준시 기준 시점으로부터의 초수로 옮겨놓을 수 있습니다 (mktime(3) 참조).
%T "%H:%M:%S" (와)과 동등합니다.
%t 탭으로 옮겨놓을 수 있습니다.
%U 1 년 중 주수 (일요일을 주의 최초일로서)를 나타낸다 10 진수 (00-53)로 옮겨놓을 수 있습니다.
%u 1 주 중 일 (월요일을 주의 최초일로서)을 나타낸다 10 진수 (1-7)로 옮겨놓을 수 있습니다.
%V 1 년 중 주수 (월요일을 주의 최초일로서)를 나타낸다 10 진수 (01-53)로 옮겨놓을 수 있습니다. 신년의 1 월 1 일을 포함한 주에 4 일 이상일이 있는 경우는, 그 주가 제 1 주가 됩니다. 그 이외의 경우는, 그 주는 전년의 마지막 주가 되어, 그 다음의 주가 제 1 주가 됩니다.
%v "%e-%b-%Y" (와)과 동등합니다.
%W 1 년 중 주수 (월요일을 주의 최초일로서)를 나타낸다 10 진수 (00-53)로 옮겨놓을 수 있습니다.
%w 1 주 중 일 (일요일을 주의 최초일로서)을 나타낸다 10 진수 (0-6)로 옮겨놓을 수 있습니다.
%X 각국의 표현으로 시각에 옮겨놓을 수 있습니다.
%x 각국의 표현으로 일자로 옮겨놓을 수 있습니다.
%Y 백년기첨부의 해를 나타내는 10 진수로 옮겨놓을 수 있습니다.
%y 백년기없음의 해를 나타내는 10 진수 (00-99)로 옮겨놓을 수 있습니다.
%Z 시간대명으로 옮겨놓을 수 있습니다.
%z (은)는 UTC 로부터의 시간대의 차이로 두어 바꿀 수 있습니다. 선두의 플러스 기호는 UTC 로부터 동쪽을 의미해, 마이너스 기호는 UTC 로부터 서쪽을 의미합니다. 계속되는 시간과 분은, 각각 2 자리수이며, 사이에 단락지어 캐릭터는 없습니다 (RFC 822 시각 헤더에 공통입니다).
%+ 각국의 표현으로 일자와 시각을 나타내는 것으로 옮겨놓을 수 있습니다 (포맷은 date(1) 에 의해 작성되는 것 것과 같습니다).
%% `%' 그리고 옮겨놓을 수 있습니다.

.
Posted by .07274.

댓글을 달아 주세요

2014.08.01 15:59

[펌] JAVA 의 ENUM 정리. I.lib()/I.lib(Java)2014.08.01 15:59

.. .. ..

.

[펌] http://iilii.egloos.com/4343065

 

java enum 정리 1 - 기본 개념

enum에 대해서 총 3부작으로 연재를 할려고 합니다.

1 - 기본 개념
2 - enum의 메쏘드
3 - java.lang.Enum 클래스와 enum의 실체

이 글은 그 첫번째로 enum에 대한 개념을 잡는 글입니다.

enum은 비스무레한 원소들이 상수로 정의되는 클래스를 대신하기 위한 것입니다. java 1.5에서 추가되었죠.
Gender를 정의하려면 enum을 사용하지 않으면 다음과 같은 class로 정의할 수 있습니다.

public class Gender{
    public static final int MALE = 1;
    public static final int FEMALE = 2;
}

위와 같은 방법이 가지는 문제점이 몇 가지 있습니다. 
첫째, MALE은 무조건 1이지만, 1이라는 숫자가 MALE만 나타내는 것은 아닙니다.
둘째, 이 Gender의 값들을 받아서 쓰는 메쏘드에서는 1,2 이외의 숫자가 들어오면 어떤 식으로 처리를 해 주어야 할지 난감합니다.

이런 경우 Gender은 다음과 같은 enum으로 정의하면 됩니다.

public enum Gender {
    MALE, FEMALE 
}

이제 Gender를 인자로 받아서 어떤 성별이 들어왔는지 찍어주는 메쏘드를 만들어봅시다.

public class GenderTest {
    public static void printGender (Gender d){
        System.out.println(d);
    }
    public static void main(String[] args) {
        printGender(Gender.MALE);
    }
}

enum은 swtich - case에서도 사용할 수 있습니다. 이번에는 남자면 "싫어", 여자면 "좋아"를 출력해주는 메쏘드를 만들어봅시다.

public class GenderTest {
    public static void printGender(Gender d){
        System.out.println(d);
    }
    public static void print(Gender d){
        switch (d) {
        case MALE: System.out.println("싫어");break;
        default:        System.out.println("좋아");break;
        }
    }
    public static void main(String[] args) {
        printGender(Gender.MALE);
        print(Gender.MALE);
        print(Gender.FEMALE);
    }
}


여기서 유의할 점은 case MALE: 부분입니다. case Gender.MALE이 아니고 그냥 MALE입니다. switch 에 enum이 들어올 경우 컴파일러가 알아서 case 쪽에는 그 enum의 타입을 적용해 줍니다.

Gender에 어떤 요소들이 들어가 있는 지 살펴볼 수 있는 방법을 소개하죠.

for(Gender g : Gender.values()){
    System.out.println(g);
}

.
TAG enum, java
Posted by .07274.

댓글을 달아 주세요

2014.07.01 11:52

[펌] 필터란 무엇인가! I.lib()/I.lib(Java)2014.07.01 11:52

.. .. ..

 

[펌] : http://javacan.tistory.com/entry/58

 

 

서블릿 2.3에 새롭게 추가된 필터가 무엇이며, 어떻게 구현하는지에 대해서 살펴본다.

필터!!

현재 서블릿 2.3 규약은 Proposed Final Draft 2 상태에 있다. 조만간 서블릿 2.3과 JSP 1.2 최종 규약이 발표될 것으로 예상되며 우리는 당연히 새롭게 추가된 것들이 무엇인지에 관심이 쏠리게 된다. 서블릿 2.3 규약에 새롭게 추가된 것 중에 필자가 가장 눈여겨 본 것은 바로 필터(Filter) 기능의 추가이다.

그 동안 필자는 서블릿 2.2와 JSP 1.1에 기반하여 웹 어플리케이션을 구현하는 동안 몇몇 부분에서 서블릿 2.2 규약의 부족한 면을 느낄 수 있었으며, 특히 사용자 인증 처리, 요청 URL에 따른 처리, XSL/T를 이용한 XML 변환(Transformation) 등 개발자들이 직접 설계해야 하는 부분이 많았었다. 하지만, 이제 서블릿 2.3 규약에 새롭게 추가된 필터(Filter)를 사용함으로써 개발자들이 고민해야 했던 많은 부분을 덜어낼 수 있게 되었다. 이 글에서는 필터가 무엇이며 어떻게 필터를 구현하는지에 대해 살펴볼 것이다.

간단하게 말해서, 필터는 'HTTP 요청과 응답을 변경할 수 있는 재사용가능한 코드'이다. 필터는 객체의 형태로 존재하며 클라이언트로부터 오는 요청(request)과 최종 자원(서블릿/JSP/기타 문서) 사이에 위치하여 클라이언트의 요청 정보를 알맞게 변경할 수 있으며, 또한 필터는 최종 자원과 클라이언트로 가는 응답(response) 사이에 위치하여 최종 자원의 요청 결과를 알맞게 변경할 수 있다. 이를 그림으로 표현하면 다음과 같다.

그림1 - 필터의 기본 구조
그림1에서 자원이 받게 되는 요청 정보는 클라이언트와 자원 사이에 존재하는 필터에 의해 변경된 요청 정보가 되며, 또한 클라이언트가 보게 되는 응답 정보는 클라이언트와 자원 사이에 존재하는 필터에 의해 변경된 응답 정보가 된다. 위 그림에서는 요청 정보를 변경하는 필터와 응답 정보를 변경하는 필터를 구분해서 표시했는데 실제로 이 둘은 같은 필터이다. 단지 개념적인 설명을 위해 그림1과 같이 분리해 놓은 것 뿐이다.

필터는 그림1에서처럼 클라이언트와 자원 사이에 1개가 존재하는 경우가 보통이지만, 여러 개의 필터가 모여 하나의 체인(chain; 또는 사슬)을 형성할 수도 있다. 그림2는 필터 체인의 구조를 보여주고 있다.

그림2 - 필터 체인
그림2와 같이 여러 개의 필터가 모여서 하나의 체인을 형성할 때 첫번째 필터가 변경하는 요청 정보는 클라이언트의 요청 정보가 되지만, 체인의 두번째 필터가 변경하는 요청 정보는 첫번째 필터를 통해서 변경된 요청 정보가 된다. 즉, 요청 정보는 변경에 변경에 변경을 거듭하게 되는 것이다. 응답 정보의 경우도 요청 정보와 비슷한 과정을 거치며 차이점이 있다면 필터의 적용 순서가 요청 때와는 반대라는 것이다. (그림2를 보면 이를 알 수 있다.)

필터는 변경된 정보를 변경하는 역할 뿐만 아니라 흐름을 변경하는 역할도 할 수 있다. 즉, 필터는 클라이언트의 요청을 필터 체인의 다음 단계(결과적으로는 클라이언트가 요청한 자원)에 보내는 것이 아니라 다른 자원의 결과를 클라이언트에 전송할 수 있다. 필터의 이러한 기능은 사용자 인증이나 권한 체크와 같은 곳에서 사용할 수 있다.

필터 관련 인터페이스 및 클래스

필터를 구현하는데 있어 핵심적인 역할을 인터페이스 및 클래스가 3개가 있는 데, 그것들은 바로 javax.servlet.Filter 인터페이스, javax.servlet.ServletRequestWrapper 클래스, javax.servlet.ServletResponseWrapper 클래스이다. 이 중 Filter 인터페이스는 클라이언트와 최종 자원 사이에 위치하는 필터를 나타내는 객체가 구현해야 하는 인터페이스이다. 그리고 ServletRequestWrapper 클래스와 SerlvetResponseWrapper 클래스는 필터가 요청을 변경한 결과 또는 응답을 변경할 결과를 저장할 래퍼 클래스를 나타내며, 개발자는 이 두 클래스를 알맞게 상속하여 요청/응답 정보를 변경하면 된다.

Filter 인터페이스

먼저, Filter 인터페이스부터 살펴보자. Filter 인터페이스에는 다음과 같은 메소드가 선언되어 있다.

  • public void init(FilterConfig filterConfig) throws ServletException
    필터를 웹 콘테이너내에 생성한 후 초기화할 때 호출한다.
  • public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException
    체인을 따라 다음에 존재하는 필터로 이동한다. 체인의 가장 마지막에는 클라이언트가 요청한 최종 자원이 위치한다.
  • public void destroy()
    필터가 웹 콘테이너에서 삭제될 때 호출된다.
위 메소드에서 필터의 역할을 하는 메소드가 바로 doFilter() 메소드이다. 서블릿 콘테이너는 사용자가 특정한 자원을 요청했을 때 그 자원 사이에 필터가 존재할 경우 그 필터 객체의 doFilter() 메소드를 호출하며, 바로 이 시점부터 필터가 작용하기 시작한다. 다음은 전형적인 필터의 구현 방법을 보여주고 있다.

  public class FirstFilter implements javax.servlet.Filter {
  
     public void init(FilterConfig filterConfig) throws ServletException {
        // 필터 초기화 작업
     }
     
     public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                          throws IOException, ServletException {
        // 1. request 파리미터를 이용하여 요청의 필터 작업 수행
        // 2. 체인의 다음 필터 처리
        chain.doFilter(request, response);        // 3. response를 이용하여 응답의 필터링 작업 수행
     }
     
     public void destroy() {
        // 주로 필터가 사용한 자원을 반납
     }
  }

위 코드에서 Filter 인터페이스의 doFilter() 메소드는 javax.servlet.Servlet 인터페이스의 service() 메소드와 비슷한 구조를 갖는다. 즉 만약 클라이언트의 자원 요청이 필터를 거치는 경우, 클라이언트의 요청이 있을 때 마다 doFilter() 메소드가 호출되며, doFilter() 메소드는 서블릿과 마찬가지로 각각의 요청에 대해서 알맞은 작업을 처리하게 되는 것이다.

위 코드를 보면 doFilter() 메소드는 세번째 파라미터로 FilterChain 객체를 전달받는 것을 알 수 있다. 이는 클라이언트가 요청한 자원에 이르기까지 클라이언트의 요청이 거쳐가게 되는 필터 체인을 나타낸다. FilterChain을 사용함으로써 필터는 체인에 있는 다음 필터에 변경한 요청과 응답을 건내줄 수 있게 된다.

위 코드를 보면서 우리가 또 하나 알아야 하는 것은 요청을 필터링한 필터 객체가 또 다시 응답을 필터링한다는 점이다. 위 코드의 doFilter() 메소드를 보면 1, 2, 3 이라는 숫자를 사용하여 doFilter() 메소드 내에서 이루어지는 작업의 순서를 표시하였는데, 그 순서를 다시 정리해보면 다음과 같다.

  1. request 파리미터를 이용하여 클라이언트의 요청 필터링
    1 단계에서는 RequestWrapper 클래스를 사용하여 클라이언트의 요청을 변경한다.
  2. chain.doFilter() 메소드 호출
    2 단계에서는 요청의 필터링 결과를 다음 필터에 전달한다.
  3. response 파리미터를 사용하여 클라이트로 가는 응답 필터링
    3 단계에서는 체인을 통해서 전달된 응답 데이터를 변경하여 그 결과를 클라이언트에 전송한다.
1단계와 3단계 사이에서 다음 필터로 이동하기 때문에 요청의 필터 순서와 응답의 필터 순서는 그림2에서 봤듯이 반대가 된다.

필터의 설정

필터를 사용하기 위해서는 어떤 필터가 어떤 자원에 대해서 적용된다는 것을 서블릿/JSP 콘테이너에 알려주어야 한다. 서블릿 규약은 웹 어플리케이션과 관련된 설정은 웹 어플리케이션 디렉토리의 /WEB-INF 디렉토리에 존재하는 web.xml 파일을 통해서 하도록 하고 있으며, 필터 역시 web.xml 파일을 통해서 설정하도록 하고 있다.

web.xml 파일에서 필터를 설정하기 위해서는 다음과 같이 <filter> 태그와 <filter-mapping> 태그를 사용하면 된다.

  <web-app>
     
     <filter>
        <filter-name>HighlightFilter</filter-name>
        <filter-class>javacan.filter.HighlightFilter</filter-class>
        <init-param>
           <param-name>paramName</param-name>
           <param-value>value</param-value>
        </init-param>
     </filter>
     
     <filter-mapping>
        <filter-name>HighlightFilter</filter-name>
        <url-pattern>*.txt</url-pattern>
     </filter-mapping>
     
  </web-app>

여기서 <filter> 태그는 웹 어플리케이션에서 사용될 필터를 지정하는 역할을 하며, <filter-mapping> 태그는 특정 자원에 대해 어떤 필터를 사용할지를 지정한다. 위 예제의 경우는 클라이언트가 txt 확장자를 갖는 자원을 요청할 경우 HithlightFilter가 사용되도록 지정하고 있다.

<init-param> 태그는 필터가 초기화될 때, 즉 필터의 init() 메소드가 호출될 때 전달되는 파라미터 값이다. 이는 서블릿의 초기화 파라미터와 비슷한 역할을 하며 주로 필터를 사용하기 전에 초기화해야 하는 객체나 자원을 할당할 때 필요한 정보를 제공하기 위해 사용된다.

<url-pattern> 태그는 클라이언트가 요청한 특정 URI에 대해서 필터링을 할 때 사용된다. 서블릿 2.3 규약의 11장을 보면 다음과 같이 url-pattern의 적용 기준을 명시하고 있다.

  • '/'로 시작하고 '/*'로 끝나는 url-pattern은 경로 매핑을 위해서 사용된다.
  • '*.'로 시작하는 url-pattern은 확장자에 대한 매핑을 할 때 사용된다.
  • 나머지 다른 문자열을 정확한 매핑을 위해서 사용된다.
에를 들어, 다음과 같이 <filter-mapping> 태그를 지정하였다고 해 보자.

     <filter-mapping>
        <filter-name>AuthCheckFilter</filter-name>
        <url-pattern>/pds/*</url-pattern>
     </filter-mapping>

이 경우 클라이언트가 /pds/a.zip 을 요청하든 /pds/b.zip 을 요청하는지에 상관없이 AuthCheckFilter가 필터로 사용될 것이다.

<url-pattern> 태그를 사용하지 않고 대신 <servlet-name> 태그를 사용함으로써 특정 서블릿에 대한 요청에 대해서 필터를 적용할 수도 있다. 예를 들면 다음과 같이 이름이 FileDownload인 서블릿에 대해서 AuthCheckFilter를 필터로 사용하도록 할 수 있다.

     <filter-mapping>
        <filter-name>AuthCheckFilter</filter-name>
        <servlet-name>FileDownload</servlet-name>
     </filter-mapping>
     
     <servlet>
        <servlet-name>FileDownload</servlet-name>
        ...
     </servlet>

래퍼 클래스

필터가 필터로서의 제기능을 하기 위해서는 클라이언트의 요청을 변경하고, 또한 클라이언트로 가는 응답을 변경할 수 있어야 할 것이다. 이러한 변경을 할 수 있도록 해 주는 것이 바로 ServletRequestWrapper와 ServletResponseWrapper이다. 서블릿 요청/응답 래퍼 클래스를 이용함으로써 클라이언트의 요청 정보를 변경하여 최종 자원인 서블릿/JSP/HTML/기타 자원에 전달할 수 있고, 또한 최종 자원으로부터의 응답 결과를 변경하여 새로운 응답 정보를 클라이언트에 보낼 수 있게 된다.

서블릿 요청/응답 래퍼 클래스로서의 역할을 수행하기 위해서는 javax.servlet 패키지에 정의되어 있는 ServletRequestWrapper 클래스와 ServletResponseWrapper 클래스를 상속받으면 된다. 하지만, 대부분의 경우 HTTP 프로토콜에 대한 요청/응답을 필터링 하기 때문에 이 두 클래스를 상속받아 알맞게 구현한 HttpServletRequestWrapper 클래스와 HttpServletResponseWrapper 클래스를 상속받는 경우가 대부분일 것이다.

HttpServletRequestWrapper 클래스와 HttpServletResponseWrapper 클래스는 모두 javax.servlet.http 패키지에 정의되어 있으며, 이 두 클래스는 각각 HttpServletRequest 인터페이스와 HttpServletResponse 인터페이스에 정의되어 있는 모든 메소드를 이미 구현해 놓고 있다. 필터를 통해서 변경하고 싶은 정보가 있을 경우 그 정보를 추출하는 메소드를 알맞게 오버라이딩하여 필터의 doFilter() 메소드에 넘겨주기만 하면 된다. 예를 들어, 클라이언트가 전송한 "company" 파리머터의 값을 무조건 "JavaCan.com"으로 변경하는 요청 래퍼 클래스는 다음과 같이 HttpServletRequestWrapper 클래스를 상속받은 후에 getParameter() 메소드를 알맞게 구현하면 된다.

  package javacan.filter;
  
  import javax.servlet.http.*;
  
  public class ParameterWrapper extends HttpServletRequestWrapper {
     
     public ParameterWrapper(HttpServletRequest wrapper) {
        super(wrapper);
     }
     
     public String getParameter(String name) {
        if ( name.equals("company") ) {
           return "JavaCan.com";
        } else {
           return super.getParameter(name);
        }
     }
  }

오버라이딩한 getParameter() 메소드를 살펴보면 값을 구하고자 하는 파라미터의 이름이 "company"일 경우 "JavaCan.com"을 리턴하고 그렇지 않을 경우에는 상위 클래스(즉, HttpServletRequestWrapper 클래스)의 getParameter() 메소드를 호출하는 것을 알 수 있다.

이렇게 작성한 래퍼 클래스는 필터 체인을 통해서 최종 자원까지 전달되어야 그 효과가 있을 것이다. 즉, 최종 자원인 서블릿/JSP에서 request.getParameter("company")를 호출했을 때 ParameterWrapper 클래스의 getParameter() 메소드가 사용되기 위해서는 ParameterWrapper 객체가 HttpServletRequest 객체를 대체해야 하는데, 이는 Filter 인터페이의 doFilter() 내에서 ParameterWrapper 객체를 생성한 후 파라미터로 전달받은 FilterChain의 doFilter() 메소드를 호출함으로써 가능하다. 좀 복잡하게 느껴질지도 모르겠으나 이를 코드로 구현해보면 다음과 같이 간단한다.

  package javacan.filter;
  
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  public class ParameterFilter implements Filter {
     
     private FilterConfig filterConfig;
     
     public ParameterFilter() {
     }
     
     public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
     }
     
     public void destroy() {
        filterConfig = null;
     }
     
     public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                          throws java.io.IOException, ServletException {
        // 요청 래퍼 객체 생성
        HttpServletRequestWrapper requestWrapper = 
                     new ParameterWrapper((HttpServletRequest)request);
        // 체인의 다음 필터에 요청 래퍼 객체 전달
        chain.doFilter(requestWrapper, response);     }
  }

응답 래퍼 클래스 역시 요청 래퍼 클래스와 비슷한 방법으로 구현된다.

앞에서도 언급했듯이 요청 정보의 변경 및 응답 정보 변경의 출발점은 래퍼 클래스이다. XML+XSL/T 기법이나 사용자 인증과 같은 것들을 최종 자원과 분리시켜 객체 지향적으로 구현하기 위해서 요청/응답 래퍼 클래스를 사용하는 것은 필수적이다. 2부에서 실제 예를 통해서 어떻게 필터와 요청/응답 래퍼 클래스를 효과적으로 사용할 수 있는 지 살펴보게 될 것이다.

필터 체인의 순서

앞에서 필터는 체인을 형성할 수 있다고 하였다. 체인을 형성한다는 것은 어떤 특정한 순서에 따라 필터가 적용된다는 것을 의미한다. 예를 들면, 여러분은 '인증필터->파라미터 변환 필터->XSL/T 필터->자원->XSL/T 필터->파라미터 변환 필터->인증필터'와 같이 특정 순서대로 필터를 적용하길 원할 것이다. 서블릿2.3 규약은 다음과 같은 규칙에 기반하여 필터 체인 내에서 필터의 적용 순서를 결정한다.

  1. url-pattern 매칭은 web.xml 파일에 표기된 순서대로 필터 체인을 형성한다.
  2. 그런 후, servlet-name 매칭이 web.xml 파일에 표기된 순서대로 필터 체인을 형성한다.
결론

이번 1 부에서는 서블릿 2.3 규약에 새롭게 추가된 필터가 무엇인지 그리고 필터를 어떻게 구현하며 또한 필터를 어떻게 서블릿이나 JSP와 같은 자원에 적용할 수 있는지에 대해서 알아보았다. 아직 구체적으로 필터의 응용방법에 대해서 설명하지 않았기 때문에 필터의 장점이 머리에 떠오르지 않을것이다. 다음 2 부에서는 구체적으로 필터의 예를 살펴봄으로써 필터의 활용함으로써 얻게 되는 장점에 대해서 살펴보도록 하자.

관련링크:

 

.
Posted by .07274.

댓글을 달아 주세요

.. .. ..

 

[펌] : 출처 : http://www.gurubee.net/pages/viewpage.action?pageId=26740202&

Servlet의 이해 및 간단예제

1. Servlet의 이해

1.1 Servlet 이란

  • Servlet은 웹에서 JAVA 프로그래밍을 구현하기 위해 탄생 함.
  • JAVA 로 구현된 CGI(Common Gateway Interface) 라고들 흔히 말함
  • HTTP protocol 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속하여 개발하며, Servlet은 Container에 의해서 실행되고, 관리된다.
  • HTML 변경시 Servlet을 재컴파일 해야 하는 단점이 있다.

1.2 Servlet Container란

  • HTTP 요청을 받아서 Servlet을 실행시키고, 그 결과를 사용자 브라우저에게 전달해주는 기능을 제공하는 컴포넌트 이다.
  • Servlet을 실행하고 생명주기를 관리하는 역할을 한다.
  • Servlet과 웹 서버(Apache, nginx..)가 서버 통신 할 수 있는 방법을 제공한다.
  • 멀티 스레딩을 지원하여 클라이언트의 다중 요청을 알아서 처리해준다.
  • 대표적인 Conatainer에는 Tomcat, jetty, jboss 등이 있다.

1.3 Servlet 동작과정

  • ① 사용자가 URL을 클릭하면 HTTP Request를 Servlet Container에 보낸다.
  • ② Servlet Container는 HttpServletRequest, HttpServletResponse 두 객체를 생성한다.
  • ③ 사용자가 요청한 URL을 분석하여 어느 서블릿에 대한 요청인지 찾는다. (DD를 참조하여 분석)
  • ④ 컨테이너는 서블릿 service() 메소드를 호출하며, POST, GET여부에 따라 doGet() 또는 doPost()가 호출된다.
  • ⑤ doGet() or doPost() 메소드는 동적인 페이지를 생성한 후 HttpServletResponse객체에 응답을 보낸다.
  • ⑥ 응답이 완료되면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다.
DD (배포서술자, Deployment Descriptor) = web.xml
  • Servlet, Error Page, Listener, Fillter, 보안 설정등 Web Application의 설정 파일이다.
  • URL과 실제 서블릿의 매핑 정보도 담고 있다.
  • 하나의 웹 어플리케이션에 하나만 존재한다.
  • 보통 Web Document Root 디렉토리에 WEB-INF 폴더 아래 web.xml 파일로 존재한다.

1.4 JSP의 동작구조

2. Servlet 간단예제

2.1 Servlet 예제 코드 작성

  • src/main/java 폴더 아래에 com.oracleclub.study.servlet 패키지를 생성하고 아래의 HelloServlet을 생성한다.
  • 모든 JAVA 파일은 직접 코딩해 주세요
com.oracleclub.study.servlet.HelloServlet.java
/*
 * HelloServlet.java 2012. 9. 14.
 *
 * Copyright oracleclub.com All rights Reserved.
 */
package com.oracleclub.study.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet 간단 예제
 * 
 * @author : oramaster
 * 
 */
@SuppressWarnings("serial")
public class HelloServlet extends HttpServlet {

    // 대부분의 Servlet은 doGet 또는 doPost만 작성하며,
    // 컨테이너가 생성한 Request와 Response 객체를 전달 받는다.
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.setContentType("text/html; charset=UTF-8");

        // Response 객체의 PrintWriter를 사용해 브라우저에 HTML을 출력한다.
        PrintWriter out = resp.getWriter();
        out.println("<HTML><HEAD><TITLE>HelloServlet</TITLE></HEAD>");
        out.println("<BODY>");
        out.println("<H2> Clinet IP: " + req.getRemoteAddr() + "</H2>");
        out.println("<H2> Client Host : " + req.getRemoteHost() + "</H2>");
        out.println("<H2> Request URI : " + req.getRequestURI() + "</H2>");
        out.println("</BODY></HTML>");
    }
}

2.2 URL과 Servlet 매핑하기

  • HelloServlet 작성이 완료 되었다면, 배포서술자(DD=web.xml) 파일에 URL 매핑을 기술한다.
web.xml
<servlet>
   <servlet-name>hello</servlet-name>  <!-- DD 안에서 사용될 이름을 지정한다. -->
   <servlet-class>com.oracleclub.study.servlet.HelloServlet</servlet-class>  <!-- Servlet 클래스 이름을 기술한다. -->
</servlet>

<servlet-mapping>
   <servlet-name>hello</servlet-name>        <!-- Servlet 클래스의 DD안에서 정의한 이름 -->
   <url-pattern>/servlet/hello</url-pattern>  <!-- 클라이언트가 요청하게 될 이름. -->
</servlet-mapping>
  • 배포서술자에서 서블릿 관련 항목을 간단히 설명하면 아래와 같다.
    • <servlet> : <servlet-name>과 <servlet-class>를 연결 한다.
    • <servlet-name> : DD 안에서 사용될 이름
    • <servlet-class> : 자바 클래스 이름
    • <url-pattern> : 클라이언트가 요청하게 될 이름
    • <servlet-mapping> : <servlet-name>과 <url-pattern>을 연결 한다.

2.3 Tomcat 연동 하기

  • 톰캣 다운로드 클릭 후 압축해제 한다.
  • 배포서술자까지 작성이 완료되었다면 톰캣을 연동하여 실행해 보자
  • 이클립스 <Servers>에서 <New>→<Server>를 실행한다.
  • <그림2-3>과 같이 <Tomcatv6.0 Server>를 선택한 후 <Server name> 을 web-project로 입력한다.
  • <Server runtime environment> 가 설정되어 있지 않다면 <Add> 버튼을 클릭하여 압축해제 한 Tomcat 디렉토리를 선택한다.
  • 강의에서는 Tomcat 6.x 버전을 기준으로 하였으며, 개인의 버전에 맞추어서 선택하면 된다.
  • Next 버튼을 클릭하고 위와 같이 spring-project를 [STUDY:Add]한 후 Finish 버튼을 클릭한다.

2.4 서블릿 실행

2.5 Apache+Tomcat연동 후 서블릿 실행

  • 정상적으로 호출이 된다면 Apache와 연동을 해보자. 좀 전에 테스트한 http-vhost.conf 파일의 DocumentRoot를 spring-project의 webapps 디렉토리로 변경하고 Apache를 restart하면 된다.
  • JkMount 설정에 /servlet/ 디렉토리도 추가해 주자
http-vhost.conf 파일 설정
<VirtualHost *:80>
    ServerName test.apache.org
    DocumentRoot C:\workspace\project\spring-project\webapps 
 
# URL중 jsp로 오는 Request만 Tomcat에서 처리 함
JkMount  /*.jsp  spring-project 

# 아래의 spring-project는 workers.properties에서 등록한 worker이름 이다.
# servlet 예제 실행을 위해서 추가
JkMount  /servlet/*  spring-project
</VirtualHost> 

2.6 URL과 Servlet을 간단하게 매핑하기

  • 위 예제에서 간단하게 HelloServlet을 실행하였는데, 만약 서블릿 클래스가 굉장히 많아 진다면, <servlet> , <servlet-mapping> 설정이 서블릿의 두 배만큼 많아 질 것이다.
  • 톰캣에서는 서블릿 매핑 설정을 간단하게 할 수 있는 기능을 제공하며, 톰캣 서버의 web.xml(이클립스에서는 <Servers> <spring-project-config>의 web.xml) 에서 아래 부분의 주석만 해제하면 된다.
web.xml 파일 설정
<!-- 122라인 -->
<servlet>
      <servlet-name>invoker</servlet-name>
      <servlet-class>
        org.apache.catalina.servlets.InvokerServlet
      </servlet-class>
      <init-param>
          <param-name>debug</param-name>
          <param-value>0</param-value>
      </init-param>
      <load-on-startup>2</load-on-startup>
  </servlet>

<!-- 382라인 -->
  <servlet-mapping>
      <servlet-name>invoker</servlet-name>
      <url-pattern>/servlet/*</url-pattern>
  </servlet-mapping>
  • Tomcat Server의 web.xml 수정 후 이클립스를 다시 실행한다.
  • spring-project의 web.xml 에서 아래와 같이 servlet 이름만 지정하고 <servlet-mapping> 설정은 제거한다.
web.xml
<servlet>
   <servlet-name>hello</servlet-name>  <!-- DD 안에서 사용될 이름을 지정한다. -->
   <servlet-class>com.oracleclub.study.servlet.HelloServlet</servlet-class>  <!-- Servlet 클래스 이름을 기술한다. -->
</servlet>
  • Tomcat Server를 재시작 한 후 http://test.apache.org/servlet/hello URL로 접속하여 정상 접속이 되는지 확인해보자
  • Invoker를 이용한 매핑의 경우 클라이언트 URL은 /servlet/servlet-name 이 된다.

3. 톰캣 startup 시 오류

3.1 404 Not Found 오류

  • <Server> → <spring-project> → <Web Moduls>에서 Path가 아래와 같이 공백으로 되어 있는지 확인한다.

3.2 java.lang.SecurityException

  • 톰캣이 startup시 "Caused by: java.lang.SecurityException: Servlet of class org.apache.catalina.servlets.InvokerServlet is privileged and cannot be loaded by this web application" 에러가 발생한다면 Tomcat Server의 server.xml 파일에서 <Context> 태그에 privileged="true" 옵션을 추가하면 된다.

3.3 java.lang.ClassNotFoundException

  • 톰캣이 startup시 "java.lang.ClassNotFoundException" 오류가 발생하면 .classpath의 MAVEN2_CLASSPATH_CONTAINER 부분을 확인한다.
  • 아래와 같이 attributes의 /WEB-INF/lib 폴더를 추가한다.
  • Project Clean, Tomcat Clean 한 후 다시 start 해보자
.classpath의 MAVEN2_CLASSPATH_CONTAINER 설정
    <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER" >
       <attributes>
            <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
        </attributes>
    </classpathentry>

-- STS 버전
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
	    <attributes>
            <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
        </attributes>
	</classpathentry>
  • <Project> → <Clean>
  • <Server> → <Clean>

문서정보

 

'I.lib() > I.lib(Java)' 카테고리의 다른 글

[펌] JAVA 의 ENUM 정리.  (0) 2014.08.01
[펌] 필터란 무엇인가!  (0) 2014.07.01
Java Servlet 이란? ( 개념 및 예제 )  (0) 2014.01.09
jstat 사용법  (0) 2014.01.03
JVM에서 Pid 를 이용하여 Process 정보 읽기 (Attach api)  (0) 2014.01.02
J2EE 란?  (0) 2013.10.30
.
Posted by .07274.

댓글을 달아 주세요

2014.01.03 11:10

jstat 사용법 I.lib()/I.lib(Java)2014.01.03 11:10

.. .. ..

 

[펌] : http://5dol.tistory.com/182

 

 

우선 간단히 확인하면 아래처럼 나온다. jstat -옵션 -pid -시간 하면 된다.
ex) ~]jstat -gc 16543 1000

저건 pid 16543(java)를 1초에 한번씩 결과값을 보여달란거다.

pid는 ps -efw | grep java로 알아내면 된다.

~] jstat --help

 invalid argument count
Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

Definitions:
  <option>      An option reported by the -options option
  <vmid>        Virtual Machine Identifier. A vmid takes the following form:
                     <lvmid>[@<hostname>[:<port>]]
                Where <lvmid> is the local vm identifier for the target
                Java virtual machine, typically a process id; <hostname> is
                the name of the host running the target Java virtual machine;
                and <port> is the port number for the rmiregistry on the
                target host. See the jvmstat documentation for a more complete
                description of the Virtual Machine Identifier.
  <lines>       Number of samples between header lines.
  <interval>    Sampling interval. The following forms are allowed:
                    <n>["ms"|"s"]
                Where <n> is an integer and the suffix specifies the units as
                milliseconds("ms") or seconds("s"). The default units are "ms".
  <count>       Number of samples to take before terminating.
  -J<flag>      Pass <flag> directly to the runtime system.



옵션은 다음과 같다.

 옵션명 내용 
 class  클래스 로더의 동작에 관한 통계 데이터
 compiler  HotSpot Just-in-Time 컴파일러의 동작에 관한 통계 데이터
 gc  가베지 컬렉트된 heap의 동작에 관한 통계 데이터
 gccapactiy  세대마다의 용량과 대응하는 영역에 관한 통계 데이터
 gccause  가베지 콜렉션 통계 데이터의 개요 (-gcutil 와 같다)와 직전 및 현재 (적용 가능한 경우)의 가베지 콜렉션 이벤트의 원인
 gcnew  New 세대의 동작에 관한 통계 데이터
 gcnewcapacity  New 세대의 사이즈와 대응하는 영역에 관한 통계 데이터
 gcold  Old 세대 및 Permanent 세대의 동작에 관한 통계 데이터
 gcoldcapacity  Old 세대의 사이즈에 관한 통계 데이터
 gcpermcapacity  Permanent 세대의 사이즈에 관한 통계 데이터
 gcutil  가베지 콜렉션 통계 데이터의 개요
 printcompilation HotSpot 컴파일 방법의 통계 데이터

각 옵션에 대한 컬럼에 대한 설명은 다음과 같다.

-class  클래스 로더의 통계 데이터
 Loaded  Bytes  Unloaded  Bytes  Time
 로드 된 클래스의 수  로드 된 K 바이트수  언로드된 클래스의 수  언로드된 K 바이트수  클래스의 로드나 언로드 처리에 필요로 한 시간

-compiler HotSpot Just-In-Time 컴파일러의 통계 데이터
 Compiled  Failed  Invalid  Time  FailedType  FailedMethod
 실행된 컴파일 태스크의 수  실패한 컴파일 태스크의 수  무효로 된 컴파일 태스크의 수  컴파일 태스크의 실행에 필요로 한 시간  마지막에 실패한 컴파일의 컴파일 타입  마지막에 실패한 컴파일의 클래스명과 메소드

-gc 가비지 컬렉트된 heap의 통계 데이터
 컬럼명  설명
 S0C  Survivor 영역 0 의 현재의 용량 (KB)
 S1C  Survivor 영역 1 의 현재의 용량 (KB)
 S0U  Survivor 영역 0 의 사용율 (KB)
 S1U  Survivor 영역 1 의 사용율 (KB)
 EC  Eden 영역의 현재의 용량 (KB)
 EU  Eden 영역의 사용율 (KB)
 OC  Old 영역의 현재의 용량 (KB)
 OU  Old 영역의 사용율 (KB)
 PC  Permanent 영역의 현재의 용량 (KB)
 PU  Permanent 영역의 사용율 (KB)
 YGC  Young 세대의 GC 이벤트수
 YGCT  Young 세대의 가베지 콜렉션 시간
 FGC  풀 GC 이벤트수
 FGCT  풀 가베지 콜렉션 시간
 GCT  가베지 콜렉션의 합계 시간

-gccapacity 메모리프르 세대 및 영역 용량

 컬럼명 설명 
 NGCMN  New 세대의 최소 용량 (KB)
 NGCMX  New 세대의 최대 용량 (KB)
 S0C  Survivor 영역 0 의 현재의 용량 (KB)
 S1C  Survivor 영역 1 의 현재의 용량 (KB)
 EC  Eden 영역의 현재의 용량 (KB)
 OGCMN  Old 세대의 최소 용량 (KB)
 OGCMX  Old 세대의 최대 용량 (KB)
 OGC  Old 세대의 현재의 용량 (KB)
 OC  Old 영역의 현재의 용량 (KB)
 PGCMN  Permanent 세대의 최소 용량 (KB)
 PGCMX  Permanent 세대의 최대 용량 (KB)
 PGC  Permanent 세대의 현재의 용량 (KB)
 PC  Permanent 영역의 현재의 용량 (KB)
 YGC  Young 세대의 GC 이벤트수
 FGC  풀 GC 이벤트수
 NGC  New 세대의 현재의 용량 (KB)

-gcutil 가베지 콜렉션 통계 데이터의 개요
 컬럼명  설명
 S0  Survivor 영역 0 의 사용율 (현재의 용량에 대한 퍼센티지)
 S1  Survivor 영역 1 의 사용율 (현재의 용량에 대한 퍼센티지)
 E  Eden 영역의 사용율 (현재의 용량에 대한 퍼센티지)
 O  Old 영역의 사용율 (현재의 용량에 대한 퍼센티지)
 P  Permanent 영역의 사용율 (현재의 용량에 대한 퍼센티지)
 YGC  Young 세대의 GC 이벤트수
 YGCT  Young 세대의 가베지 콜렉션 시간
 FGC  풀 GC 이벤트수
 FGCT  풀 가베지 콜렉션 시간
 GCT  가베지 콜렉션총시간

-gccause GC 이벤트를 포함한 가베지 콜렉션 통계 데이터(gcutil에 두개 컬럼이 추가됨)
 컬럼명  설명
 LGCC  마지막 가베지 콜렉션의 원인
 GCC  현재의 가베지 콜렉션의 원인

-gcnew New 세대의 통계 데이터
 컬럼명  설명
 S0C  Survivor 영역 0 의 현재의 용량 (KB)
 S1C  Survivor 영역 1 의 현재의 용량 (KB)
 S0U  Survivor 영역 0 의 사용율 (KB)
 S1U  Survivor 영역 1 의 사용율 (KB)
 TT  전당 들어가 귀의치
 MTT  최대 전당 들어가 귀의치
 DSS  적절한 Survivor 사이즈 (KB)
 EC  Eden 영역의 현재의 용량 (KB)
 EU  Eden 영역의 사용율 (KB)
 YGC  Young 세대의 GC 이벤트수
 YGCT  Young 세대의 가베지 콜렉션 시간

-gcold 옵션 Old 및 Permanent 세대의 통계 데이터
 컬럼명 설명 
 PC  Permanent 영역의 현재의 용량 (KB)
 PU  Permanent 영역의 사용율 (KB)
 OC  Old 영역의 현재의 용량 (KB)
 OU  Old 영역의 사용율 (KB)
 YGC  Young 세대의 GC 이벤트수
 FGC  풀 GC 이벤트수
 FGCT  풀 가베지 콜렉션 시간
 GCT  가베지 콜렉션총시간

-gcoldcapacity Old 세대의 통계 데이터
 컬럼명 설명 
 OGCMN  Old 세대의 최소 용량 (KB)
 OGCMX  Old 세대의 최대 용량 (KB)
 OGC  Old 세대의 현재의 용량 (KB)
 OC  Old 영역의 현재의 용량 (KB)
 YGC  Young 세대의 GC 이벤트수
 FGC  풀 GC 이벤트수
 FGCT  풀 가베지 콜렉션 시간
 GCT  가베지 콜렉션총시간

-printcompilation HotSpot 컴파일 방법의 통계 데이터

 컬럼명 설명 
 Compiled  실행된 컴파일 태스크의 수
 Size  메소드의 바이트 코드의 바이트수
 Type  컴파일 타입
 Method  컴파일 방법을 특정하는 클래스명과 메소드명. 클래스명에서는, 이름 공간의 단락 문자로서 「.」(은)는 아니고 「/」이 사용된다. 메소드명은, 지정된 클래스내의 메소드이다. 이러한 2 개의 필드의 형식은, HotSpot -XX:+PrintComplation 옵션과 대응하고 있다


사용 방법

jstat -gcutil -h5 16543 1000 10

jstat를 -gcutil 옵션을 주고 5개씩 출력마다 헤더를 출력(h5)하고 1초마다 출력하되 10개씩 보여준다.

.
Posted by .07274.

댓글을 달아 주세요

.. .. ..

 

[출처] Attach API|작성자 날씬한곰

 

Java EE/초급 2007/09/03 14:08

저자 JZ Ventures사의 사장 겸 대표 컨설턴트 John Zukowski

이 아티클의 영문 원본은 http://java.sun.com/mailers/techtips/corejava/2007/tt0807.html#2
에서 볼수 있습니다.

Java 플랫폼을 다룰 때 일반적으로 표준 java.*javax.* 라이브러리를 사용하여 프로그래밍한다. 그러나 Sun JDK(Java Development Kit)에서 이 라이브러리만 제공하는 것은 아니다. JDK 설치 디렉토리 아래 lib 디렉토리에 있는 tools.jar 파일에서 몇 가지 추가 API를 제공한다. javadoc 도구와 Attach API라는 API의 확장이 지원됨을 알 수 있다.

이름이 암시하는 것처럼, Attach API는 대상 VM(virtual machine)에 연결할 수 있게 해준다. 다른 VM에 연결하면 현재 상황을 모니터링하고 문제가 발생하기 전에 이를 발견할 수도 있다. Attach API 클래스는 com.sun.tools.attachcom.sun.tools.attach.spi 패키지에 있지만, 일반적으로 com.sun.tools.attach.spi 클래스를 직접 사용하는 일은 없다.

사용하지 않을 .spi 패키지에 있는 유일한 클래스를 비롯하여 전체 API는 총 7개의 클래스로 구성된다. 그 중에 3개는 exception 클래스이고 하나는 permission이다. 따라서 VirtualMachine 및 이와 관련된 VirtualMachineDescriptor 클래스를 제외하곤 학습할 내용이 그리 많지 않다.

VirtualMachine 클래스는 특정 JVM 인스턴스를 나타낸다. VirtualMachine 클래스에 프로세스 ID를 제공하여 JVM에 연결한 다음 사용자 정의 동작을 수행하도록 관리 에이전트를 로드한다.

VirtualMachine vm = VirtualMachine.attach (processid);
String agent = ...
vm.loadAgent(agent);

VirtualMachine을 얻는 또 다른 방법은 시스템에 알려진 VM의 목록을 요청하고 관심 있는 하나를 선택하는 것인데, 흔히 이름을 기준으로 한다.

String name = ...
List vms = VirtualMachine.list();
for (VirtualMachineDescriptor vmd: vms) {
    if (vmd.displayName().equals(name)) {
        VirtualMachine vm = VirtualMachine.attach(vmd.id());
        String agent = ...
        vm.loadAgent(agent);
        // ...
    }
}

이 에이전트로 무엇을 할 수 있는지 알아보기에 앞서 고려해야 할 사항 두 가지가 있다. 첫 번째는, loadAgent() 메소드가 설정을 에이전트에 전달하는 두 번째 인수 옵션을 갖는다는 것이다. 여기서는 여러 개의 옵션을 전달할 가능성이 있는 단 하나의 인수만 존재하므로, 여러 개의 인수는 쉼표로 구분된 목록의 형태로 전달된다.

vm.loadAgent (agent, "a=1,b=2,c=3");그런 다음 에이전트는 다음과 비슷한 코드로 그 인수를 분할하는데, 인수가 에이전트의 args 변수에 전달되었다고 가정한다.

String options[] = args.split(",");
for (String option: options)
    System.out.println(option);
}


두 번째로 언급할 점은 현재 VM을 대상 VM으로부터 분리하는 방법이다. 이는 detach() 메소드를 통해 수행된다. loadAgent()를 사용하여 에이전트를 로드한 다음 detach()해야 한다.

JMX 에이전트가 JDK와 함께 제공된 management-agent.jar 파일에 있다. tools.jar와 동일한 디렉토리에 있는 JMX 관리 에이전트는 원격 JMX 에이전트의 MBean Server를 시작하고 그 서버와의 MBeanServerConnection을 얻게 해준다. 그리고 이를 통해 원격 VM에 있는 스레드 등을 나열할 수 있다.

다음 프로그램이 바로 그런 작업을 수행한다. 먼저 식별된 VM과 연결한다. 그런 다음 실행 중인 원격 JMX 서버를 찾고, 아직 시작된 것이 없으면 하나를 시작한다. ,code>management-agent.jar 파일은 원격 VM의 java.home을 찾아 지정한다. 반드시 로컬일 필요는 없다. 일단 연결되면 MBeanServerConnection을 얻으며, 그로부터 ManagementFactory에서 스레드나 ThreadMXBean 등을 쿼리한다. 마지막으로, 스레드와 그 상태의 목록이 표시된다.

import java.lang.management.*;
import java.io.*;
import java.util.*;
import javax.management.*;
import javax.management.remote.*;
import com.sun.tools.attach.*;

public class Threads {

  public static void main(String args[]) throws Exception {
    if (args.length != 1) {
      System.err.println("Please provide process id");
      System.exit(-1);
    }
    VirtualMachine vm = VirtualMachine.attach(args[0]);
    String connectorAddr = vm.getAgentProperties().getProperty(
      "com.sun.management.jmxremote.localConnectorAddress");
    if (connectorAddr == null) {
      String agent = vm.getSystemProperties().getProperty(
        "java.home")+File.separator+&qut;lib&qut;+File.separator+
        "management-agent.jar";
      vm.loadAgent(agent);
      connectorAddr = vm.getAgentProperties().getProperty(
        "com.sun.management.jmxremote.localConnectorAddress");
    }
    JMXServiceURL serviceURL = new JMXServiceURL(connectorAddr);
    JMXConnector connector = JMXConnectorFactory.connect(serviceURL);
    MBeanServerConnection mbsc = connector.getMBeanServerConnection();
    ObjectName objName = new ObjectName(
      ManagementFactory.THREAD_MXBEAN_NAME);
    Set<ObjectName> mbeans = mbsc.queryNames(objName, null);
    for (ObjectName name: mbeans) {
      ThreadMXBean threadBean;
      threadBean = ManagementFactory.newPlatformMXBeanProxy(
        mbsc, name.toString(), ThreadMXBean.class);
      long threadIds[] = threadBean.getAllThreadIds();
      for (long threadId: threadIds) {
        ThreadInfo threadInfo = threadBean.getThreadInfo(threadId);
        System.out.println (threadInfo.getThreadName() + &qut; / &qut; +
            threadInfo.getThreadState());
      }
    }
  }
}


이 프로그램을 컴파일하려면 해당 CLASSPATH에 tools.jar가 있어야 한다. JAVA_HOME이 Attach API가 포함된 Java SE 6 설치 디렉토리로 설정되었다고 가정하면, 다음 줄이 프로그램을 컴파일한다.
> javac -cp %JAVA_HOME%/lib/tools.jar Threads.java

여기서 프로그램을 실행할 수 있지만, 연결할 대상은 없다. 따라서 프레임을 표시하는 간단한 Swing 프로그램을 소개한다. 특별한 것은 없으며, 그저 알아볼 만한 스레드 이름 몇 개를 나열할 뿐이다.

import java.awt.*
import javax.swing.*

public class MyFrame {
  public static void main(String args[]) {
    Runnable runner = new Runnable() {
      public void run() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 300);
        frame.setVisible(true);
      }
    };
    EventQueue.invokeLater(runner);
  }
}

한 창에서 MyFrame 프로그램을 실행하고, 다른 창에서 Threads 프로그램을 실행할 준비를 한다. 시스템이 원격 VM과 연결할 수 있도록 동일한 런타임 위치를 공유해야 한다.

일반적인 시작 명령으로 MyFrame을 시작한다.
> java MyFrame

그런 다음 실행 중인 애플리케이션의 프로세스 ID를 찾아야 한다. 바로 여기서 jps 명령이 진가를 발휘한다. 사용 중인 Java 런타임 디렉토리에 대해 시작된 모든 VM의 프로세스 ID를 나열하는 것이다. 실제로는 아래와 다른 프로세스 ID가 출력될 것이다.

> jps
5156 Jps
4276 MyFrame

jps 명령 자체가 Java 프로그램이므로 그 역시 목록에 나타난다. 여기서 4276이 Threads 프로그램으로 전달되어야 한다. 실제 ID는 이와 다를 것이다. 그런 다음 Threads를 실행하면 실행 중인 스레드의 목록을 덤프한다.

> java -cp %JAVA_HOME%/lib/tools.jar;. Threads 4276

JMX server connection timeout 18 / TIMED_WAITING
RMI Scheduler(0) / TIMED_WAITING
RMI TCP Connection(1)-192.168.0.101 / RUNNABLE
RMI TCP Accept-0 / RUNNABLE
DestroyJavaVM / RUNNABLE
AWT-EventQueue-0 / WAITING
AWT-Windows / RUNNABLE
AWT-Shutdown / WAITING
Java2D Disposer / WAITING
Attach Listener / RUNNABLE
Signal Dispatcher / RUNNABLE
Finalizer / WAITING
Reference Handler / WAITING


JMX 관리 에이전트를 사용하면 스레드를 나열하는 것 이상의 훨씬 많은 일을 할 수 있다. 예를 들어, ThreadMXBeanfindDeadlockedThreads() 메소드를 호출하여 교착 상태의 스레드를 찾을 수 있다.

직접 에이전트를 만드는 것은 더 간단한 편이다. 애플리케이션에서 main() 메소드를 필요로 하는 것과 비슷하게 에이전트는 agentMain() 메소드를 갖는다. 이는 어떤 인터페이스에도 속하지 않는다. 시스템은 그저 정확한 인수가 매개변수로 설정된 것을 찾아야 함을 알 뿐이다.

import java.lang.instrument.*

public class SecretAgent {
   public static void agentmain(String agentArgs,
       Instrumentation instrumentation) {
     // ...
   }
}

에이전트를 사용하려면 컴파일된 클래스 파일을 JAR 파일로 패키지화하고 매니페스트에서 Agent-Class를 지정해야 한다.

Agent-Class: SecretAgent

그러면 프로그램의 main() 메소드가 원래 Threads 프로그램보다 약간 더 짧아지는데, 원격 JMS 커넥터와 연결할 필요가 없기 때문이다. 여기서는 새로 패키지화된 에이전트를 사용하도록 JAR 파일 참조를 변경하면 된다. 그런 다음 SecretAgent 프로그램을 실행하면 시작하는 즉시, 즉 애플리케이션의 main() 메소드가 호출되기도 전에 agentmain() 메소드가 실행된다. Applet처럼, 어떤 인터페이스에도 속하지 않은 작업을 수행하도록 멋진 이름이 지정된 또 다른 메소드들이 존재한다.

Threads 프로그램을 사용하여 또 다른 VM을 모니터링하고, 일부 스레드를 교착 상태로 보낸 다음 이 차단된 VM과 계속 통신할 수 있는 방법을 표시해 본다.

Attach API를 위한 API 문서를 참조한다. 또한 JVM TI(Java Virtual Machine Tool Interface)에 대한 자료도 읽어볼 수 있다. 거기서는 Attach API를 사용해야 한다.

[출처] Attach API|작성자 날씬한곰

.
Posted by .07274.

댓글을 달아 주세요

2013.10.30 22:43

J2EE 란? I.lib()/I.lib(Java)2013.10.30 22:43

.. .. ..

http://cafe.naver.com/javakoreait/29

.
Posted by .07274.

댓글을 달아 주세요

.. .. ..

SocketChannel 의 설정을 알아보던중에 아래와 같은 설정을 확인했다.

 

SocketChannel.socket().setTcpNoDelay(true);

 

무엇을 하는 설정인지 알아보다 귀찮음에 뒤로 미루어 두었다가 다시 한번 알아보고 정리한다.

 

JavaDoc 을 살펴보면 아래와 같이 설명이 되어있다.

 

" Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). "

 

한글로 풀어보니 대충

 

" TCP_NoDelay 기능을 사용/비사용 (Nagle`s 알고리즘을 On/OFF) "

 

하는 기능으로 조심스래 유추된다.

 

그래서 Nagle`s  알고리즘이 무엇인지 찾아보니 아래와 같은 뜻임을 알수 있었다.

 

Nagle알고리즘? 네트워크 상에 패킷의 수를 줄이기 위해 개발된 알고리즘

 

1. 일반 네트워크 통신방법

- 일반적인 통신알고리즘은 데이터는 패킷으로 만들어 보낸다는 것이며 수신호스트는 이에 대한 ACK를 보낸다는 것입니다. 예를 들어, A,B 두 호스트가 통신을 합니다. A B에게 'Nagle'라는 데이터를 보내기 원하면, 먼저 'N'이라는 데이터를 패킷으로 만들어 출력버퍼로 보냅니다. 그리고 ACK를 받고 안받고 관계없이 'a'를 패킷으로 만들어 보내고 이어서 'g', 'l', 'e' 각 데이터를 패킷으로 만들어 보낼 것입니다. 수신호스트로부터의 ACK가 언제 오는가는 전혀 관계가 없고언제 오든지 오기만 하면 되는 것입니다.

 

2. Nagle 알고리즘

- 네트웍에서 Nagle 알고리즘은 "가능하면 조금씩 여러 번 보내지 말고 한번에 많이 보내라(Effective TCP)" 라는 원칙을 기반으로 만들어진 알고리즘입니다.

- Nagle 알고리즘의 원리는 ACK를 받은 다음에 데이터를 보내고 ACK를 받을 때까지 출력버퍼의 데이터를 저장하였다가 ACK를 받으면 버퍼의 데이터를 모두 패킷으로 만들어 보낸다는 것입니다. 예를 들어 A 'N'이라는 데이터를 패킷으로 만들어 보내고, 계속해서 다음 데이터를 보내는 것이 아니라 출력버퍼로 보내어 저장시켜 둡니다. 그러다가 ACK가 오면 출력버퍼에 저장된 'agle'라는 데이터를 보냅니다.


- TCP 소켓은 Default Nagle 알고리즘을 적용하고 있습니다.

 

3. Nagle 알고리즘의 장단점

  - 장점네트워크의 효율성이 높아짐. (똑같은 데이터를 보내더라도 생산하는 패킷이 적음)

  - 단점 : 송신 호스트가 ACK를 받을 때까지 기다려야 하므로 전송 속도가 느려짐

 

4. Nagle 알고리즘의 중단

- 몇몇 네트웍 관련 프로그램에서는 네트웍의 전송량이나 부하보다는 빠른 응답속도를 더 중요시 여기는 상황이 있습니다. 그러한 때에는 TCP_NODELAY  라는 옵션을 사용하여 Nagle 알고리즘을 제거 할 수 있습니다.

 

- TCP_NODELAY 옵션이

     1(TRUE) : Nagle 알고리즘을 적용하지 않습니다.

     2(FALSE): Nagle 알고리즘을 적용합니다.

 

int opt_val = TRUE;

setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, sizeof(opt_val));

 

해당 옵션의 사용은 네트웍 부하를 극대화 시켜주면서 서버의 전체적인 성능을 무척 감소하기때문에 꼭 필요한 경우에만 매우 주의를 해서 사용해야 합니다.

- 전송은 작은 단위로 자주 이루어지지만 즉각적인 응답은 필요 없는 어플리케이션에서만 사용 되어야 합니다.(마우스 움직임 같은)

 

- Nagle 알고리즘은 리얼타임시스템에서의 제어와 특히나 인터렉티브한 키 입력을 하는 어플리케이션에서는 안 좋은 영향을 미칩니다. 선택적으로 Nagle 알고리즘을 통과하는 한가지 방법은 Out-of-bind 메시지 시스템을 쓰는 것입니다. 그러나 이것은 내용물에 제약이 있고 또 다른 문제(순서의 상실: loss of sequentiality)를 일으킬 수 있습니다.

 

 

위 글을 읽어보고 유추되는 setTcpNoDelay 라는 기능은 아래와 같이 정리할수 있다.

 

SocketChannel.socket().setTcpNoDelay(true);

  -- Tcp에 딜레이가 없도록(NoDelay) 하겠다.

      (즉 Nagle 알고리즘을 적용하면 Tcp에 Delay 가 있으수 있으니 Nagle 알고리즘을 적용하지 않겠다.)

 

SocketChannel.socket().setTcpNoDelay(false);

  -- 위와 반대의 개념.

 

일단 위와같이 정리가 된다.

 

보고 도움이 되셨으면 댓글하나 달아주고 가시면 안잡아 먹습니다.

 

ps : 알아보고 설명해달랬더니 모르겠다고 하고 프로젝트를 나가버린 이X영씨는 이글보면 술한잔 사라~!

 

 

.
Posted by .07274.

댓글을 달아 주세요

  1. Favicon of http://4518.ccgenevois.com/uggfrance.php BlogIcon ugg 2013.07.25 03:37 신고  댓글주소  수정/삭제  댓글쓰기

    지금은 반짝반짝 빛이 나겠지,, 하지만 시간이 흐르면 그빛은 사라저버릴거야,지금 우리처럼

  2. asdfasdfas 2015.03.16 23:59 신고  댓글주소  수정/삭제  댓글쓰기

    마침 궁금햇엇는데 잘보고갑니다 감사합니다.

  3. eeee 2015.04.22 15:48 신고  댓글주소  수정/삭제  댓글쓰기

    도움이 되었습니다. 감사합니다.

  4. Favicon of http://blog.naver.com/eominsuk55 BlogIcon BoxResin 2016.02.26 20:57 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다~

.. .. ..

[펌] : http://kldp.org/node/165

 댓글들을 정리하였습니다.

 

 

첫번째 정리

 

예전에 제가 TIME_WAIT 상태에 대해 정리했던 글입니다. 한번 읽어보시길 바랍니다.
Unix나 Linux 상에서 네트워크 프로그래밍을 하실때는 W.Richard Stevens가 저술한 Unix Network Programming을 참고하시면
많은 도움이 됩니다.(유닉스 네트워크 프로그래밍 서적의 바이블이죠.)

Quote:
TCP는 여러개의 State를 가질수 있습니다. 예를들어 CLOSED(연결이 닫혔을때) LISTEN(연결을 기다리고 있을때), ESTABLISHED(연결이 되었을때) 등등의 상태를 가질수 있습니다. 이중에서 TIME_WAIT라는 상태가 있는데, 이해하기 가장 어려운 부분인것 같습니다. TIME_WAIT 상태는 다음과 같은 경우에 발생합니다. 우선 Client와 Server가 TCP로 연결이 되어 있다고 가정합시다. 이때 클라이언트가 연결을 끊으려면 close함수를 호출합니다. 이 함수를 호출하면 서버에 FIN segment를 보내게 됩니다. 그러면 서버는 이 메시지를 받고 클라이언트가 접속을 끊으려고 하는 것을 알게됩니다. 따라서 서버가 CLOSE_WAIT 상태가 되면서 클라이언트에게 ack segment를 보냅니다. 즉 "네가 접속을 끊는 다는 신호를 받았다" 이런 의미입니다. 이 메시지를 받으면 클라이언트는 FIN_WAIT_2 상태가 됩니다. 이 상태에서 서버는 자신의 socket을 close하고 다시 클라이언트에게 FIN segment를 보냅니다. 즉 자신도 연결을 닫았다는 신호를 클라이언트에게 보내는 것입니다. 이 메시지를 받으면 클라이언트는 ack segment를 보내면서 TIME_WAIT 상태가 됩니다. 즉 서로간의 확인하에 완전히 연결이 끊기게 됩니다. 근데 이 상태에서 곧바로 CLOSED 상태가 되는 것이 아니라 2 MSL(maximum segment lifetime - 1분~4분) 동안 TIME_WAIT상태를 유지합니다. 왜 곧바로 CLOSED 상태가 되지 않고 일정시간 동안 TIME_WAIT 상태가 되는 것일까요?

뭔가 이상하지 않습니까? 그 이유는 다음과 같습니다. TCP는 신뢰성을 보장해 주는 프로토클 입니다.(UDP는 아니지요.) 따라서 연결시에도 신뢰성을 보장하기 위하여 Three-way handshake라는 기법을 사용하여 연결을 하고 종료시에도 위와같이 복잡한 과정을 거쳐 서로가 close된것을 확인하게 되는 것입니다. TIME_WAIT 상태도 이와같은 신뢰성 보장을 위한 한가지 방법이라고 보시면 됩니다.

Unix Network Programming에 보면 TIME_WAIT 상태가 있는 이유에 대해 다음과 같이 설명하였습니다.

1. to implement TCP's full-duplex connection termination reliably, and
2. to allow old duplicate segments to expire in the network.

흠 첫번째는 신뢰성있는 연결 종료를 위한 것이라고 쓰여있습니다. 근데 두번째는 무엇일까요?
network에 있는 duplicate segments들이 소멸시키기 위해서?? 무슨 소리인지 -_-;;
이 두가지에 대하여 자세히 설명해 보겠습니다.

 

먼저 첫번째에 대해서 설명하겠습니다.
이것은 말그대로 신뢰성있은 연결 종료를 위한것입니다. 다음과 같은 상황을 가정합시다. 클라이언트가 FIN_WAIT_2 상태에서 서버의 FIN segment를 받으면 TIME_WAIT상태가 되면서 서버에 ack segment를 보낸다고 하였습니다. 하지만 이 ack segment가 네트워 크의 오류로 인해 서버에 도착하지 못할수도 있습니다. 그런 경우라면 서버에서는 일정시간 이후에 다시 클라이언트에게 FIN segment를 보냅니다. 자신이 응답을 못받았으니 다시 보내달라는 의미지요. 만약 클라이언트가 CLOSED 상태 즉 연결이 닫혀 있는 상태에서 서버가 다시 보낸 이 FIN segment를 받으면 어떻게 될까요? 그런 경우라면 ack대신 RST라는 segment를 보내게됩니다. 즉 CLOSED 되면서 이전에 서버와 연결했던 정보들이 전부 없어졌으므로 서버가 다시 요청을 하면 "나는 너를 모른다. 왜 이상한 메시지를 보내느냐?" 하면서 서버가 원하는 ack 대신 RST라는 segment를 보내게 되는 것입니다. 이런 상황을 방지하기 위하여 일정시간 동안 TIME_WAIT라는 상태를 유지하여 서버가 다시 FIN을 보냈을때 대답할수 있게 해줍니다.

 

두번째에 대한 설명입니다.
다음과 같은 상황을 가정해 봅시다.
우선 현재 111.111.111.111:23 번하고 111.111.111.112:1500번이 연결되어 있다고 합시다.둘이 막 패킷을 주고 받다가 둘이 연결을 정상적으로 끊었다고 가정합시다. 그 후에 둘이 곧바로 연결을 해서 방금전과 마찬가지로 111.111.111.111:23 과 111.111.111.112:1500으로 연결되었다고 합시다. 근데 여기서 문제가 발생하였습니다. 바로 이전에 연결이 성립되었을때 111번에서 112번으로 보낸 패킷하나가 라우터의 오류로 인터넷을 뺑뺑이 돌다가 이전 연결이 끊어지고 지금 새로운 연결이 되었을때 112번에 도착했습니다. 무슨 소리냐구요? 예를 들어 라우터 A와 B가 있습니다. 근데 라우터의 일시적인 오류로 라우터 A의 데이타가 B로 전송하면 B가 다시 A로 그 데이타를 전송하여 순간적인 루프에 빠질수가 있을 수도 있습니다. 이렇게 루프에 빠지던 놈이 이전 연결이 끝나고 새로운 연결이 생겼을 때 도착한다면 문제가 발생하겠죠? 즉 원하지 않는 데이타가 전송되었으니 오류가 발생할 수 도 있는 것입니다. 이것을 방지하기 위하여 TIME_WAIT 상태를 둡니다. TIME_WAIT상태에 있는 동안은 같은 연결이 발생하지 못하도록 방지합니다. 즉 이전에 내가 연결되었던 포트가 1500번이라면 다음 연결은 현재 1500번이 TIME_WAIT이므로 1501번으로 연결되게 됩니다. 그렇게 하면 위와같은 문제를 해결할 수 있습니다. 보통 TIME_WAIT상태는 2 MSL입니다. 즉 인터넷 상에서 패킷이 존재하는 시간보다 길게 설정됩니다. 그러므로 TIME_WAIT상태가 끊나면 인터넷 상에서는 이전 연결에 보내졌던 패킷이 모두 소멸되었다고 확신할 수 있으므로 새로운 연결을 만들어도 문제가 발생하지 않는것입니다..

Dream, Passion and Challenge..

 

 

두번째 정리

네트워크 프로그래밍을 하다보면 반드시, 이 문제(TIME_WAIT)를 안 겪고 넘어갈래야 안 겪고
넘어갈 수가 없습니다. 만약, 겪어보지 못했다면 공부를 다시하고 이 분야에서 충분한 경력도
없으신 분일 겁니다.. 이 TIME_WAIT 가 발생하는 문제는 심각한 문제입니다. 왜? 그러느냐?
엄청나게 빠른속도로 접속하고 엄청나게 빠른 속도로 종료되는 시스템에서는 이 TIME_WAIT 문제는
심각한 상태를 만들어냅니다.. 자원고갈되는 사태를 벌어지게 만듭니다. 위에 최초 질문자가
구현한 프로그램은 while 로 도는 무한정의 접속 및 종료의 클라이언트 연결을 만듭니다.
이런 프로그램은 포트 스캐너 같은 프로그램과 유사한 면이 있습니다. 저도 예전에 경험한 적이
있는데 수많은 접속과 종료가 순식간에 발생하면 서버 뿐만 아니라 클라이언트에서도 자원고갈이
발생합니다.. netstat 로 보게되면 TIME_WAIT 상태가 산더미 같이 쌓이게되죠.. 그럼 나중에
접속을 더이상 할 수가 없게됩니다.. 왜? 자원고갈 상태가 되어버립니다.. 소켓이 죄다 열려
있는 상태인데 사용할 포트는 65535 가 최대거든요? 이 문제가 서버에서도 발생합니다..
그래서, 클라이언트가 명확하게 접속을 끊는 경우와 서버가 명확하게 접속을 끊을 경우에는 반드시
TIME_WAIT 없이 깨끗한 상태로 끊어져야 합니다. 그래야 접속폭풍이 일어나는 기업의 상용서비스에
대응할 수 있게되는거죠.. 대기업 서버가 자원고갈이 발생해서야되겠습니까? 무식한 서버가 되는
거죠.. 그리고, 그런 문제는 자바에서는 이미 처리되고 있습니다.. 아~주 깔끔하게.. 그럼, 그게
어떻게 한거냐?

(정답)
- 서버에서 클라이언트를 명시적으로 끊었을때 TIME_WAIT 가 발생하지 않으려면..?
shutdown(sock, sd_both);
closesocket();
소켓을 닫기 전에 셧다운을 시켜야 한다. 그럼, TIME_WAIT 없이 깔끔하게 끊어진다.

- 클라이언트에서 명시적으로 끊어서 TIME_WAIT 가 발생하지 않으려면?
그건 위에 댓글 단 사람들이 이미 설명했다. SO_LINGER 써라..

-(요약)
서버에서 폭풍접속 종료에 깔끔하게 TIME_WAIT 없이 명시적 종료를 하려면 shutdown 을
쓰고, 클라이언트에서 폭풍접속 종료에 깔끔하게 TIME_WAIT 없이 명시적 종료를 하려면
SO_LINGER 에서 타임을 0 으로 바꿔라..
이렇게하는 이유는 어마어마한 속도로 접속과 종료를 반복해서 무한정 돌려야하는 클라이언트와
서버 프로그래밍에서 자원이 고갈되지 않도록(디스크립터 자원고갈 발생 방지) 하기 위함이다.
이걸 지키지 않으면 최초 접속자가 헤메는 그 증상이 나타난다. 즉, 서버와 클라이언트 양쪽
에서 이 규칙을 지켜야 합니다. 어느한쪽이 안지키면 그 안지킨 한쪽은 폭풍접속 및 종료에
있어서 결국에는 자원고갈되며 병신되는거죠..

 

 

어렵구나 네트워크는.. 에구..

 

'I.lib() > I.lib(Java)' 카테고리의 다른 글

J2EE 란?  (0) 2013.10.30
Socket 의 setTcpNoDelay 관련 정리. (Nagle 알고리즘 관련)  (4) 2013.06.17
Network 통신중 TIME_WAIT 관련 정보 정리  (0) 2013.06.17
Deque (덱) 요약  (0) 2013.06.05
[펌] ByteBuffer 설명 정리  (0) 2013.04.23
[펌] 제한자 정리  (0) 2013.04.18
.
Posted by .07274.

댓글을 달아 주세요