카테고리:

3 분 소요

Netty

Netty는 비동기 이벤트 기반 네트워크 애플리케이션 프레임워크이다. Java 기반의 NIO(Non-blocking I/O)를 바탕으로 서버 및 클라이언트와 같은 네트워크 애플리케이션을 빠르고 쉽게 개발할 수 있다.

이전에 자주 사용했던 MINA와 Netty는 NIO를 사용한다는 점에선 같지만, 많은 부분에서 다르다. Netty는 성능과 확장성을 우선시한 모듈식 설계와 더 큰 커뮤니티를 바탕으로 개발자가 네트워크 운영을 위한 프로그램을 작성할 수 있다. 또한, Netty의 아키텍처와 스레딩 모델은 처리량이 많은 서버 애플리케이션을 위한 탁월한 성능을 제공한다.

https://stackshare.io/stackups/mina-vs-netty

EchoServer 예제

  • MainServer.kt
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.ChannelInitializer
import io.netty.channel.ChannelOption
import io.netty.channel.EventLoopGroup
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.logging.LogLevel
import io.netty.handler.logging.LoggingHandler

object MainServer {
    @JvmStatic
    fun main(args: Array<String>) {
        // Configure the server.
        val bossGroup: EventLoopGroup = NioEventLoopGroup(1)
        val workerGroup: EventLoopGroup = NioEventLoopGroup()
        val serverHandler = MainServerHandler()
        try {
            val b = ServerBootstrap()
            b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel::class.java)
                .handler(LoggingHandler(LogLevel.INFO))
                .option(ChannelOption.SO_BACKLOG, 100)
                .childHandler(object : ChannelInitializer<SocketChannel>() {

                    public override fun initChannel(ch: SocketChannel) {
                        val p = ch.pipeline()
                        p.addLast(Codec.PacketDecoder())
                        p.addLast(Codec.PacketEncoder())
                        p.addLast(serverHandler)
                    }
                })

            // Start the server.
            val f = b.bind(Setting().serverPort).sync()

            // Wait until the server socket is closed.
            f.channel().closeFuture().sync()
        } finally {
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully()
            workerGroup.shutdownGracefully()
        }
    }
}
  • MainServerHandler.kt
import io.netty.channel.Channel
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter

@Sharable
class MainServerHandler : ChannelInboundHandlerAdapter() {

    override fun channelActive(ctx: ChannelHandlerContext) {
        println("[Connect] " + ctx.channel().remoteAddress())
    }

    override fun channelInactive(ctx: ChannelHandlerContext) {
        println("[DisConnect] " + ctx.channel().remoteAddress())
        ctx.channel().close()
    }

    override fun channelRead(ctx: ChannelHandlerContext, msg: Any?) {
        println("[Send] " + channel.remoteAddress() + " " + msg)
        ctx.write(msg)
    }

    override fun channelReadComplete(ctx: ChannelHandlerContext) {
        ctx.flush()
    }

    override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
        // Close the connection when an exception is raised.
        cause.printStackTrace()
        ctx.close()
    }
}

재작성 하면서 느낀점

  1. Java와 호환을 위한 어노테이션이 많다.
  2. Java 10부터도 var이 생겨서 추론형 변수를 알고 있었으나, val이라는 새로운 것이 등장해서 뭔가 싶었지만, final 같은 불변 타입이었다.
  3. override를 할 때 어노테이션이 아니라, 함수 선언 앞에 붙는다.
  4. 함수를 선언할 때 fun이라고 선언한다.
  5. 매개변수의 형식은 콜론 뒤에 붙으며, ?가 붙을 때만 nullable로 null을 허용해준다.
  6. new를 사용한 객체 생성이 없다.

태그: annotation, EchoServer, java, jvmstatic, Kotlin, netty, nio, Nullable, val

업데이트: