본문 바로가기
슬기로운 자바 개발자 생활/모던 자바와 Reactive

네티 Netty 프레임워크 공부 01 (예제 첨부)

by 슬기로운 동네 형 2022. 12. 21.
반응형

네티 Netty 프레임워크 공부 01 (예제 첨부)


네티(Netty)란?

네티 홈페이지에서 네티를 아래와 같이 소개하고 있다.

https://netty.io/index.html

네티는 빠르게 개발가능한 유지보수, 고성능 서버, 클라이언트

비동기 이벤트드리븐 네트워크 애플리케이션 프레임워크다.

 

설명은 뒤로 하고 정말 빠르게 만들 수 있는지 간단한 예제로 시작해 보자.

 

내가 아는 네티 그리고 미리 알아두면 좋은 내용.

 

 Spring5 WebFlux의 코어에도 사용되었다.

 이벤트 드리븐, 비동기, MSA 아키텍처에 대한 지식을 습득하게 되면 왜 Netty를 공부할 만한 가치가 있는지 느끼게 된다.

 

Neetty.io 홈페이지

 

Netty: Home

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty is a NIO client server framework which enables quick and easy development of network applications s

netty.io


실습 준비물

  • 네티 개발환경 설정 (pom.xml)
  • Discard Server 서버 예제
  • Putty Telnet 클라이언트 설치 및 설정

네티 프레임워크로 간단하고 빠르게 비동기 DiscardServer를 구축해 보자.

홈페이지에 jar 파일이 어디 있는지 모르겠다.

몇 개월 전과 달라진듯하다.

Maven을 이용해서 netty-netty-4.1.86 버전으로 개발을 해본다.

 

이클립스든 인텔리 J든 크게 어려울 건 없다. 아래 Maven repository 의존성만 추가하면 된다.

<dependencies>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.86.Final</version>
</dependency>
</dependencies>

소스도 첨부한다. 참고로 Inteli J 용이다.

nettyEdu.zip
0.01MB


DiscardServer  구현

DiscardServer는 말 그대로 아무것도 하지 않는 서버다.

첫 번째 예제는 간단하게 클라이언트에서 보낸 글자를 찍는 정도만 만들어 본다.

자바 파일은 2개다.

 

  • DiscardServer.java 
  • DiscardServerHandler.java

DiscardServer.java

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class DiscardServer {

    private int port;

    public DiscardServer(int port) {
        this.port = port;
    }
    public void run() throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new DiscardServerHandler()); //1
                            //ch.pipeline().addLast(new DiscardServerHandler());
                        }
                    });
                    
                    //옵션
                    //.option(ChannelOption.SO_BACKLOG, 128)
                    //.childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture f = b.bind(port).sync(); // 2
            f.channel().closeFuture().sync();
        }finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception{
        int port = 8080;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }
        new DiscardServer(port).run();
    }
}

DiscardServerHandler.java

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        ByteBuf in = (ByteBuf) msg;
        try {
            while (in.isReadable()) {
                System.out.print((char) in.readByte());
                System.out.flush();
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

 


 Discard 서버 예제에서는 클라이언트로부터 데이터를 8080번 포트로 수신하는 간단한 기능을 수행한다.

 즉, Putty나 Telnet 프로그램으로 부터 받은 데이터를 DiscardServerHandler의 channelRead 메서드에서 System.out.print로 표시하는 정도다.

 클라이언트에게 어떤 응답도 되돌려 주는 기능은 없다.

 

 이 예제는 클라이언트의 입력을 받아들일 포트를 지정하는 메인 서버 DiscardServer.java와 클라이언트로부터 받은 입력 데이터를 처리하는 핸들러 DiscardServerHandler.java로 나뉜다.

 

 main 메서드에서는 서비스할 포트를 지정하고 run 메서드를 실행시킨다.

 run 메서드는 네티의 이벤트 루프, 부트스트랩, 채널 파이프라인, 핸들러 등의 클래스를 사용하는 코드를 갖고 있다.

 

DiscardServer.java 소스코드의 1번은 접속된 클라이언트로부터 수신된 데이터를 처리할 핸들러를 지정한다.

DiscardServer.java 소스코드의 2번은 생성자로 받은 포트번호를 bind 메서드로 접속할 포트를 지정한다.

 

DiscardServerHandler.java 클래스는 핸들러 기능을 담당하며, (추후 클라이언트 인증, 필터, 인터셉터 등등)

데이터가 수신되면, chaannelRead() 메서드를 자동 실행시킨다.


실행해보자

Putty 나 Window Telent 기능을 이용해서 데이터를 우리가 만든 DiscardServer 서버에 보내보자.

Telnet 8080 포트로 접속
수신한 데이터가 Console 창에 보인다.

윈도우 cmd 자체 Telnet 프로그램을 사용해서 접속도 가능하다.

제어판-윈도우기능켜기/끄기-텔넷 클라이언트 활성화
윈도우 텔넷으로 접속 엔터
cmd를 이용해서 테스트도 가능
프로젝트구조


마치며

 네티 홈페이지의 소개대로 빠르게 비동기 이벤트 드리븐 방식의 서버를 만들었다.

 네티 홈페이지 소개대로 빠르게 간단한 DiscardServer를 구축해 봤다.

 

 네트워크 프로그래밍은 많은 배경정보가 필요하며 꽤 집입장벽도 높다고 생각한다. 어쨌든 어렵다.

 

 네티는 전 세계 수많은 개발자가 사용하는 범용 자바 네트워크 프레임워크다.

 대표적으로 엘라스틱 서치, 아파치 스파크, 스프링 부트 같은 오픈소스 프레임워크 내부에서 네트워크 코어에 사용된다.

 

 다음 시간에는 클라이언트 프로그램도(양방향 수신 가능) 만들어 본다.

 


포스팅에 참고된 내용은 지금은 절판된 자바 네트워크소녀 네티입니다.

http://www.yes24.com/Product/Goods/20600128

 

자바 네트워크 소녀 네티 - YES24

자바 네트워크 프로그래밍의 최고의 선택 Netty!이 책은 안정성과 성능을 세계적으로 인정받아 카카오톡, 애플, 트위터, 페이스북, 네이버 라인 등에서 사용하는 자바 네트워크 프레임워크 네티

www.yes24.com

 

반응형

댓글