본문 바로가기

IT for developer/Netty

Netty 예제 분석 - HTTP.snoop

HTTP.snoop

http://docs.jboss.org/netty/3.2/xref/org/jboss/netty/example/http/snoop/package-summary.html

간단한 HTTP 클라이언트와 서버를 구현하고 있다.

클라이언트 부터 살펴보자.

기존 다른 예제와 다르게 클라이언트 main 함수에서 하는일들이 참 많다.

79          bootstrap.setPipelineFactory(new HttpClientPipelineFactory(ssl));
PipelineFactory는  Anonymous 클래스를 사용하지않고 HttpClientPiplelineFactory 클래스를 별도로 생성했다.

PipelineFactory는 결국 핸들러들을 등록하는 역할을 수행하는데 좀 더 많은 핸들러를 조건에 따라 등록하기 위해 별도의 파이프라인 팩토리 클래스를 생성한 듯하다.


그밖에 차이점은 핸들러에서 write 하는 것이 아니라. main 함수에서 직접 Channel.write 함수를 호출하고 있다.
82          ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
85          Channel channel = future.awaitUninterruptibly().getChannel();
106         channel.write(request);

연결이 완료 될때 가지 대기하다가 연결 되면 요청 데이터를 전송한다.

이제 좀 더 자세히 살펴 보기위해 HttpClientPipelineFactory와 main의 나머지 부분을 살펴보자.

getPipeline 함수를 살펴보면 4가지 핸들러를 등록하는 것을 볼 수 있다.

49          if (ssl) {
50 SSLEngine engine =
51 SecureChatSslContextFactory.getClientContext().createSSLEngine();
52 engine.setUseClientMode(true);
53
54 pipeline.addLast("ssl", new SslHandler(engine));
55 }
56
57 pipeline.addLast("codec", new HttpClientCodec());
58
59 // Remove the following line if you don't want automatic content decompression.
60 pipeline.addLast("inflater", new HttpContentDecompressor());
61
62 // Uncomment the following line if you don't want to handle HttpChunks.
63 //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
64
65 pipeline.addLast("handler", new HttpResponseHandler());

ssl을 참으로 넘겼으면 SslHandler를 최우선으로 등록한다. 그리고 HttpClientCodec, HttpContentDecompressor, HttpResponseHandler를 등록한다. 마지막 HttpResponseHandler를 빼고는 모두 Netty에서 지원해주고 있는 핸들러들이다.

각 핸들러가 어떤 핸들러를 상속받고 있는지 확인하자.

Ssl: 업, 다운
HttpClientCodec: 업, 다운 
HttpContentDecompressor: 업
HttpResponseHandler: 업

다시 정리하면 클라이언트가 서버에 데이터를 전송할 때는 HttpClientCodec --> Ssl 순서로 이벤트가 처리되고 서버에서 데이터를 수신할 때는 Ssl-->HttpClientCodec-->HttpContentDecompressor-->HttpResponseHandler 순서로 이벤트가 처리된다.

Ssl:  키 교환하고 연결을 맺는 작업을 할듯하고 .. 패스

HttpClientCodec: 다운스트림에 인코더를 업스트림에 디코더를 사용한다. 데이터 전송할 때는 전송하기 위한 적절한 포멧으로 변환해주고 데이터를 수신할 때는 다시 그 데이터를 디코딩한다. (당연히 서버쪽에서도 동일한 구조를 가지고 있어야 정상적으로 데이터를 주고받을 수 있다.) 
HTTPClient.main 함수에서 아래와 같이 HttpRequest를 셋팅하는 것을 볼 수 있다. 인코더는 이 것을 ChannelBuffer 형태로 변환해주는 역할을 한다.
93          HttpRequest request = new DefaultHttpRequest(94                  HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString());95          request.setHeader(HttpHeaders.Names.HOST, host);96          request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);97          request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);

HttpContentDecompressor: 수신한 데이터가 압축되어 있다면 이를 풀어주는 역할을 한다. (HTTP 헤더를 보고 판단한다.)

HttpResponseHandler: HTTP 헤더 정보와 컨텐츠를 화면에 출력해 준다.


이제 서버를 살펴보자.

43          bootstrap.setPipelineFactory(new HttpServerPipelineFactory());

서버도 별도의 파이프라인 팩토리 클래스를 생성하여 사용하였다.
38          // Uncomment the following line if you want HTTPS39          //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();40          //engine.setUseClientMode(false);41          //pipeline.addLast("ssl", new SslHandler(engine));
43          pipeline.addLast("decoder", new HttpRequestDecoder());
44 // Uncomment the following line if you don't want to handle HttpChunks.
45 //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
46 pipeline.addLast("encoder", new HttpResponseEncoder());
47 // Remove the following line if you don't want automatic content compression.
48 pipeline.addLast("deflater", new HttpContentCompressor());
49 pipeline.addLast("handler", new HttpRequestHandler());


HttpRequestDecoder - 업
HttpResponseEncoder - 다운
HttpContentCompressor - 다운
HttpRequestHandler - 다운

클라이언트와 대응되는 핸들러들이 있다는 것을 볼 수 있다. (ssl 쓸려면 주석을 해제하면된다. line. 39~41)

클라이언트                                              서버
HTTPClientCodec              <----> HttpRequestDecoder, HttpResponseEncoder
HttpContentDecompressor   <----  HttpContentCompressor 
HttpResponseHandler         <----  HttpRequestHandler 


그밖에 별 특이 사항이 없다.

그냥 서버에서는 동일한 페이지를 응답해주도록 HttpRequestHandler에서 구현하고 있다.