프로토콜/Netty

[Java] Netty Server

기은P 2020. 9. 4. 16:05
반응형

Netty Server

 

 

 

 

1. Maven Depedency 추가

 

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


Netty
라이브러리를 이용하기 위한 디펜던시를 추가합니다. 

 

 

 

 

 

2. Server

Netty 서버를 구성하기 위해 3가지 기초 설정이 필요합니다.

EventLoopGroup 생성과 ServerBootstrap 생성 및 구성, ChannelInitializer 생성입니다.

 

public class NettyServer {
	public NettyServer() throws InterruptedException {
		EventLoopGroup group = new NioEventLoopGroup();
		
		try{
		    ServerBootstrap serverBootstrap = new ServerBootstrap();
		    serverBootstrap.group(group);
		    serverBootstrap.channel(NioServerSocketChannel.class);
		    serverBootstrap.localAddress(new InetSocketAddress("localhost", 9999));

		    serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
		        protected void initChannel(SocketChannel socketChannel) throws Exception {
		            socketChannel.pipeline().addLast(new ServerHandler());    // 핸들러 설정
		        }
		    });
		    ChannelFuture channelFuture = serverBootstrap.bind().sync();
		    channelFuture.channel().closeFuture().sync();
		} catch(Exception e){
		    e.printStackTrace();
		} finally {
		    group.shutdownGracefully().sync();
		}
	}
}

 

EventLoopGroup 생성

Netty TCP 서버를 만드는 첫 번째 단계로, EventLoopGroup을 생성해야합니다.

NettyJava NIO 를 사용하므로 NioEventLoopGroup이 생성됩니다.

 

 

ServerBootStrap 만들기

먼저 ServerBootstrap 인스턴스를 생성하고, 위 부트스트랩에 EventLoopGroup를 설정합니다.

그다음 NioServerSocketChannel클래스 인스턴스를 ServerBootstrap의 인스턴스로 설정합니다.

마지막으로 로컬 IP주소 또는 도메인 + TCP 포트로 InetSocketAddress를 설정합니다.

 

 

ChannelInitializer 생성

위에서 설정한 serverBootstrap에 자식 핸들러로 childHandler() 메서드를 호출 합니다.

이때, ChannelInitializer()를 생성해서 추상화된 initChannel()Override해줍니다.

이 함수의 인자인 SocketChannel을 통해 pipeline()을 생성하고, 이 파이프라인을 통해 들어오는 데이터를 처리하기 위한 핸들러를 붙혀줍니다.

여기서는 HelloServerHandler()를 생성해서 연결해주었습니다.

 

 

 

 

3. ServerHandler

 

public class ServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf inBuffer = (ByteBuf) msg;

        String received = inBuffer.toString(CharsetUtil.UTF_8);
        System.out.println("Server received: " + received);

        ctx.write(Unpooled.copiedBuffer("Hello " + received, CharsetUtil.UTF_8)); // 버퍼에 쓰기
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE); // 채널 파이프라인에 저장된 버퍼 전송
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

 

Handler는 클라이언트 연결에서 들어오는 데이터를 처리하는 클래스입니다.

 

소켓 채널을 통해 데이터가 수신 될 때마다 channelRead() 메서드가 호출됩니다.

 

이때 서버 핸들러 측에서는 ChannelHandlerContext를 통해 데이터를 버퍼에 써서 반환해줍니다.

channelReadComplete()는 소켓 채널로부터 읽을 수 있는 데이터가 더 이상 존재하지 않을 때 호출되는데, 마지막으로 채널을 닫아주는 역할을 합니다.

 

exceptionCaught()는 수신 또는 데이터를 전송하는 동안 예외가 발생하는 경우에 불려집니다.

여기에서 연결을 닫거나 오류 코드로 응답하는 등 어떤 일이 발생해야하는지 결정할 수 있습니다.

 

 

 

참고 사이트

http://tutorials.jenkov.com/netty/netty-tcp-server.html

 

 

 

반응형