Echo ์๋ฒ๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฉ์์ง๋ฅผ ๋ฐ์ ๊ทธ๋๋ก ๋ฐํํ๋ ์๋ฒ์
๋๋ค.
implementation 'org.springframework.boot:spring-boot-starter-webflux'
2.1 ChannelHandler ๊ตฌํ
๋จผ์ ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ChannelHandler
๋ฅผ ๊ตฌํํฉ๋๋ค. ์ด ํธ๋ค๋ฌ๋ ์์ ๋ ๋ฉ์์ง๋ฅผ ๊ทธ๋๋ก ๋ฐํํฉ๋๋ค.
@Component
class EchoServerHandler : ChannelInboundHandlerAdapter() {
private val logger = LoggerFactory.getILoggerFactory().getLogger(EchoServerHandler::class.java.name)
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
logger.info("[Echo] Received: ${(msg as ByteBuf).toString(Charset.defaultCharset())}")
ctx.write(msg)
}
override fun channelReadComplete(ctx: ChannelHandlerContext) {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(CLOSE)
}
override fun channelActive(ctx: ChannelHandlerContext) {
logger.info("[Echo] Connected to client")
}
}
2.2 ์๋ฒ ๋ถํธ์คํธ๋ฉ ์ค์
์๋ฒ๋ฅผ ์ค์ ํ๊ณ ์์ํ๊ธฐ ์ํ ๋ถํธ์คํธ๋ฉ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
@Configuration
class EchoServer (
@Value("\${netty.port:28080}")
private val port: Int,
private val echoServerHandler: EchoServerHandler,
) {
private val logger: Logger = LoggerFactory.getLogger(EchoServer::class.java)
private val group: NioEventLoopGroup = NioEventLoopGroup()
private val serverBootstrap: ServerBootstrap = ServerBootstrap()
@Bean
fun start(): ServerBootstrap {
logger.info("[Echo] Starting server on port $port")
return serverBootstrap.group(group)
.channel(NioServerSocketChannel::class.java)
.localAddress(port)
.childHandler(echoServerHandler)
.also { it.bind().sync() }
}
@PreDestroy
fun stop() {
logger.info("[Echo] Stopping server")
group.shutdownGracefully().sync()
}
}
3. Echo ํด๋ผ์ด์ธํธ ์์ฑ
Echo ์๋ฒ์ ํต์ ํ ํด๋ผ์ด์ธํธ๋ฅผ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.
3.1 ChannelHandler ๊ตฌํ
ํด๋ผ์ด์ธํธ์ ChannelHandler
๋ ์๋ฒ๋ก๋ถํฐ ์์ ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
class EchoClientHandler : SimpleChannelInboundHandler<ByteBuf>() {
private val logger = getILoggerFactory().getLogger(EchoClientHandler::class.java.name)
override fun channelRead0(p0: ChannelHandlerContext?, p1: ByteBuf?) {
logger.info("[Echo] Received: ${p1?.toString(Charset.defaultCharset())}")
}
override fun channelActive(ctx: ChannelHandlerContext) {
logger.info("[Echo] Connected to server")
ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, World!".toByteArray()))
}
}
3.2 ํด๋ผ์ด์ธํธ ๋ถํธ์คํธ๋ฉ ์ค์
ํด๋ผ์ด์ธํธ ๋ถํธ์คํธ๋ฉ ์ฝ๋๋ ์๋ฒ์ ์ฐ๊ฒฐํ๊ณ ๋ฉ์์ง๋ฅผ ์ ์กํ๋ ์์
์ ์ฒ๋ฆฌํฉ๋๋ค.
@Test
fun echoPingTest() {
val echoClientHandler = EchoClientHandler()
val group = NioEventLoopGroup()
val serverBootstrap = Bootstrap()
.group(group)
.channel(NioSocketChannel::class.java)
.remoteAddress("localhost", 28080)
.handler(object : ChannelInitializer<SocketChannel>() {
override fun initChannel(ch: SocketChannel) {
ch.pipeline().addLast(echoClientHandler)
}
})
val channelFuture = serverBootstrap.connect().sync()
channelFuture.channel().closeFuture().sync()
}
4. ์ ํ๋ฆฌ์ผ์ด์
์คํ
์ด์ ์๋ฒ์ ํด๋ผ์ด์ธํธ๋ฅผ ์คํํ์ฌ Netty ์ ํ๋ฆฌ์ผ์ด์
์ ํ
์คํธํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ EchoServer
์ main
๋ฉ์๋๋ฅผ ์คํํ์ฌ ์๋ฒ๋ฅผ ์์ํฉ๋๋ค.
๊ทธ๋ฐ ๋ค์ EchoClient
์ main
๋ฉ์๋๋ฅผ ์คํํ์ฌ ํด๋ผ์ด์ธํธ๋ฅผ ์์ํฉ๋๋ค.
ํด๋ผ์ด์ธํธ๋ ์๋ฒ์ ๋ฉ์์ง๋ฅผ ์ ์กํ๊ณ , ์๋ฒ๋ ๊ทธ ๋ฉ์์ง๋ฅผ ๊ทธ๋๋ก ํด๋ผ์ด์ธํธ์ ๋ฐํํฉ๋๋ค.
Last updated