Transport

Chapter 4: Transports

Netty๋Š” ๋‹ค์–‘ํ•œ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋งž๋Š” ์ตœ์ ์˜ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์žฅ์—์„œ๋Š” Netty์˜ ํŠธ๋žœ์ŠคํฌํŠธ ๊ตฌํ˜„๊ณผ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ์ ์ ˆํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

4.1 ํŠธ๋žœ์ŠคํฌํŠธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

ํŠธ๋žœ์ŠคํฌํŠธ์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด, ๊ฐ„๋‹จํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ†ตํ•ด OIO์™€ NIO๋ฅผ ์‚ฌ์šฉํ•œ ๋„คํŠธ์›Œํ‚น์„ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค

4.1.1 Netty ์—†์ด OIO์™€ NIO ์‚ฌ์šฉํ•˜๊ธฐ

Netty ์—†์ด OIO์™€ NIO๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ธ”๋กœํ‚น ๋ฐ ๋น„๋™๊ธฐ ๋ฒ„์ „์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

OIO๋ฅผ ์‚ฌ์šฉํ•œ ๋ธ”๋กœํ‚น ๋„คํŠธ์›Œํ‚น

public class PlainOioServer {
    public void serve(int port) throws IOException {
        final ServerSocket socket = new ServerSocket(port);  
        try {
            for (;;) {
                final Socket clientSocket = socket.accept();   
                System.out.println("Accepted connection from " + clientSocket);
                new Thread(new Runnable() {        
                    @Override
                    public void run() {
                        OutputStream out;
                        try {
                            out = clientSocket.getOutputStream();
                            out.write("Hi!\r\n".getBytes(Charset.forName("UTF-8")));
                            out.flush();
                            clientSocket.close();          
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                clientSocket.close();
                            } catch (IOException ex) {
                                // ignore on close
                            }
                        }
                    }
                }).start();                  
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

์ด ์ฝ”๋“œ๋Š” ์ ๋‹นํ•œ ์ˆ˜์˜ ๋™์‹œ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋Œ€๊ทœ๋ชจ์˜ ๋™์‹œ ์—ฐ๊ฒฐ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋น„๋™๊ธฐ ๋„คํŠธ์›Œํ‚น์œผ๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

NIO๋ฅผ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ๋„คํŠธ์›Œํ‚น

public class PlainNioServer {
    public void serve(int port) throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        ServerSocket ssocket = serverChannel.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        ssocket.bind(address);                                       
        Selector selector = Selector.open();                        
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);   
        final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
        for (;;) {
            try {
                selector.select();           
            } catch (IOException ex) {
                ex.printStackTrace();
                break;
            }
            Set<SelectionKey> readyKeys = selector.selectedKeys();    
            Iterator<SelectionKey> iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {           
                        ServerSocketChannel server = (ServerSocketChannel)key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate());     
                        System.out.println("Accepted connection from " + client);
                    }
                    if (key.isWritable()) {                  
                        SocketChannel client = (SocketChannel)key.channel();
                        ByteBuffer buffer = (ByteBuffer)key.attachment();
                        while (buffer.hasRemaining()) {
                            if (client.write(buffer) == 0) {    
                                break;
                            }
                        }
                        client.close();             
                    }
                } catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException cex) {
                        // ignore on close
                    }
                }
            }
        }
    }
}

์ด ์ฝ”๋“œ๋Š” ๋น„๋™๊ธฐ I/O๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งŽ์€ ์ˆ˜์˜ ๋™์‹œ ์—ฐ๊ฒฐ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ฝ”๋“œ ๋ณต์žก์„ฑ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

4.1.2 Netty๋ฅผ ์‚ฌ์šฉํ•œ OIO์™€ NIO

Netty๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํŠธ๋žœ์ŠคํฌํŠธ ๋ณ€๊ฒฝ์ด ํ›จ์”ฌ ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค. Netty์˜ ํ†ต์ผ๋œ API ๋•๋ถ„์— ์ฝ”๋“œ ๋ฒ ์ด์Šค๋ฅผ ๊ฑฐ์˜ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Netty๋ฅผ ์‚ฌ์šฉํ•œ ๋ธ”๋กœํ‚น ๋„คํŠธ์›Œํ‚น

public class NettyOioServer {
    public void server(int port) throws Exception {
        final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8")));
        EventLoopGroup group = new OioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();    
            b.group(group)
                .channel(OioServerSocketChannel.class)         
                .localAddress(new InetSocketAddress(port))
                .childHandler(new ChannelInitializer<SocketChannel>() { 
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { 
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);  
                            }
                        });
                    }
                });
            ChannelFuture f = b.bind().sync();       
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();          
        }
    }
}

Netty๋ฅผ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ๋„คํŠธ์›Œํ‚น

public class NettyNioServer {
    public void server(int port) throws Exception {
        final ByteBuf buf = Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"));
        EventLoopGroup group = new NioEventLoopGroup();   
        try {
            ServerBootstrap b = new ServerBootstrap();      
            b.group(group)
             .channel(NioServerSocketChannel.class)
             .localAddress(new InetSocketAddress(port))
             .childHandler(new ChannelInitializer<SocketChannel>() { 
                @Override
                public void initChannel(SocketChannel ch) throws Exception{
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {   
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);
                        }
                    });
                }
            });
            ChannelFuture f = b.bind().sync();      
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully().sync();         
        }
    }
}

Netty๋Š” ๋™์ผํ•œ API๋ฅผ ๋…ธ์ถœํ•˜๋ฏ€๋กœ, ํŠธ๋žœ์ŠคํฌํŠธ ๊ตฌํ˜„์— ์ƒ๊ด€์—†์ด ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

4.2 ํŠธ๋žœ์ŠคํฌํŠธ API

ํŠธ๋žœ์ŠคํฌํŠธ API์˜ ํ•ต์‹ฌ์€ Channel ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๋ชจ๋“  I/O ์ž‘์—…์— ์‚ฌ์šฉ๋˜๋ฉฐ, Channel ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

classDiagram
    AbstractChannel <|-- NioSocketChannel
    AbstractChannel <|-- OioServerSocketChannel
    AbstractChannel : +ChannelPipeline pipeline
    AbstractChannel : +ChannelConfig config
    class NioSocketChannel{
        +void doWrite()
        +void doRead()
    }
    class OioServerSocketChannel{
        +void doConnect()
        +void doAccept()
    }

Channel์—๋Š” ChannelPipeline๊ณผ ChannelConfig๊ฐ€ ํ• ๋‹น๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ChannelConfig๋Š” ์ฑ„๋„์˜ ๋ชจ๋“  ์„ค์ •์„ ๋ณด์œ ํ•˜๋ฉฐ ํ•ซ ๋ณ€๊ฒฝ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ํŠธ๋žœ์ŠคํฌํŠธ๋Š” ๊ณ ์œ ํ•œ ์„ค์ •์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ChannelConfig์˜ ํ•˜์œ„ ํƒ€์ž…์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Channel์€ ์œ ์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— java.lang.Comparable์˜ ํ•˜์œ„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์„ ์–ธ๋˜์–ด ์ˆœ์„œ๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ AbstractChannel์˜ compareTo() ๊ตฌํ˜„์€ ๋‘ ๊ฐœ์˜ ๊ณ ์œ ํ•œ Channel ์ธ์Šคํ„ด์Šค๊ฐ€ ๋™์ผํ•œ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

ChannelPipeline๊ณผ ChannelHandler

ChannelPipeline์€ ๋ชจ๋“  ChannelHandler ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด์œ ํ•˜์—ฌ ์ธ๋ฐ”์šด๋“œ ๋ฐ ์•„์›ƒ๋ฐ”์šด๋“œ ๋ฐ์ดํ„ฐ์™€ ์ด๋ฒคํŠธ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ChannelHandler๋“ค์€ ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋กœ์ง์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ChannelHandler์˜ ์‚ฌ์šฉ ์˜ˆ:

  • ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ํ˜•์‹์—์„œ ๋‹ค๋ฅธ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜

  • ์˜ˆ์™ธ ์•Œ๋ฆผ ์ œ๊ณต

  • Channel์ด ํ™œ์„ฑํ™” ๋˜๋Š” ๋น„ํ™œ์„ฑํ™”๋  ๋•Œ ์•Œ๋ฆผ ์ œ๊ณต

  • Channel์ด EventLoop์— ๋“ฑ๋ก๋˜๊ฑฐ๋‚˜ ๋“ฑ๋ก ํ•ด์ œ๋  ๋•Œ ์•Œ๋ฆผ ์ œ๊ณต

  • ์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์•Œ๋ฆผ ์ œ๊ณต

์ฃผ์š” Channel ๋ฉ”์„œ๋“œ

๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ค๋ช…

eventLoop

์ฑ„๋„์— ํ• ๋‹น๋œ EventLoop์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

pipeline

์ฑ„๋„์— ํ• ๋‹น๋œ ChannelPipeline์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

isActive

์ฑ„๋„์ด ํ™œ์„ฑ ์ƒํƒœ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

localAddress

๋กœ์ปฌ SocketAddress๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

remoteAddress

์›๊ฒฉ SocketAddress๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

write

์›๊ฒฉ ํ”ผ์–ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์”๋‹ˆ๋‹ค. ์ด ๋ฐ์ดํ„ฐ๋Š” ChannelPipeline์„ ํ†ตํ•ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค

flush

์ด์ „์— ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์ € ํŠธ๋žœ์ŠคํฌํŠธ์— ํ”Œ๋Ÿฌ์‹œํ•ฉ๋‹ˆ๋‹ค.

4.3 ํฌํ•จ๋œ ํŠธ๋žœ์ŠคํฌํŠธ

Netty๋Š” ๋‹ค์–‘ํ•œ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ์— ๋งž๋Š” ์ตœ์ ์˜ ์†”๋ฃจ์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” Netty๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ฃผ์š” ํŠธ๋žœ์ŠคํฌํŠธ๋“ค์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

4.3.1 NIOโ€”๋…ผ๋ธ”๋กœํ‚น I/O

NIO๋Š” Netty์˜ ์ฃผ์š” ๋…ผ๋ธ”๋กœํ‚น ํŠธ๋žœ์ŠคํฌํŠธ์ž…๋‹ˆ๋‹ค. java.nio.channels ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์„ ํƒ๊ธฐ(Selector) ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹จ์ผ ์Šค๋ ˆ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ์—ฐ๊ฒฐ์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

NIO์˜ ํŠน์ง•

  • ๋น„๋™๊ธฐ I/O ์ž‘์—… ์ง€์›: ๋ชจ๋“  I/O ์ž‘์—…์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

  • ๋†’์€ ํ™•์žฅ์„ฑ: ๋งŽ์€ ์ˆ˜์˜ ๋™์‹œ ์—ฐ๊ฒฐ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ œ๋กœ ์นดํ”ผ ํŒŒ์ผ ์ „์†ก ์ง€์›: FTP ๋˜๋Š” HTTP์™€ ๊ฐ™์€ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

public class NioServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new EchoServerHandler());
                 }
             });

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

4.3.2 Epoll ๋„ค์ดํ‹ฐ๋ธŒ ๋…ผ๋ธ”๋กœํ‚น ํŠธ๋žœ์ŠคํฌํŠธ

Epoll์€ ๋ฆฌ๋ˆ…์Šค์—์„œ ๋†’์€ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๋…ผ๋ธ”๋กœํ‚น ํŠธ๋žœ์ŠคํฌํŠธ์ž…๋‹ˆ๋‹ค. ๋ฆฌ๋ˆ…์Šค์˜ epoll ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋†’์€ ์„ฑ๋Šฅ๊ณผ ํ™•์žฅ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Epoll์˜ ํŠน์ง•

  • ๋ฆฌ๋ˆ…์Šค ์ „์šฉ: ๋ฆฌ๋ˆ…์Šค ์šด์˜ ์ฒด์ œ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

  • ๋†’์€ ์„ฑ๋Šฅ: ๋ฆฌ๋ˆ…์Šค์˜ ๋„ค์ดํ‹ฐ๋ธŒ epoll ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๊ทน๋Œ€ํ™”ํ•ฉ๋‹ˆ๋‹ค.

  • ๋‚ฎ์€ ์ง€์—ฐ ์‹œ๊ฐ„: ๋Œ€๊ทœ๋ชจ ๋™์‹œ ์—ฐ๊ฒฐ์—์„œ ๋‚ฎ์€ ์ง€์—ฐ ์‹œ๊ฐ„์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

4.3.3 OIOโ€”๋ธ”๋กœํ‚น I/O

OIO๋Š” ์ „ํ†ต์ ์ธ ๋ธ”๋กœํ‚น I/O ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋Š” ํŠธ๋žœ์ŠคํฌํŠธ์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋‚˜ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ์˜ ์ด์ฃผ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

OIO์˜ ํŠน์ง•

  • ๋ธ”๋กœํ‚น I/O ์ž‘์—… ์ง€์›: ๊ฐ„๋‹จํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

  • ์ ์€ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ: ๊ฐ ์—ฐ๊ฒฐ์ด ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์— ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

public class OioServer {
    public static void main(String[] args) {
        EventLoopGroup bossGroup = new OioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup)
             .channel(OioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new EchoServerHandler());
                 }
             });

            ChannelFuture f = b.bind(8080).sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
        }
    }
}

4.3.4 ๋กœ์ปฌ ํŠธ๋žœ์ŠคํฌํŠธ

Netty๋Š” ๊ฐ™์€ JVM ๋‚ด์—์„œ ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ์œ„ํ•ด ๋กœ์ปฌ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ํŠธ๋žœ์ŠคํฌํŠธ๋Š” ์‹ค์ œ ๋„คํŠธ์›Œํฌ ์ฃผ์†Œ์— ๋ฐ”์ธ๋”ฉ๋˜์ง€ ์•Š๊ณ  ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ํ†ต์‹ ์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ์ปฌ ํŠธ๋žœ์ŠคํฌํŠธ์˜ ํŠน์ง•

  • ๊ฐ™์€ JVM ๋‚ด์—์„œ์˜ ํ†ต์‹  ์ง€์›: ์‹ค์ œ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋„คํŠธ์›Œํฌ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋น ๋ฅธ ๋ฐ์ดํ„ฐ ์ „์†ก: ๋†’์€ ์„ฑ๋Šฅ์„ ์š”๊ตฌํ•˜๋Š” ๋‚ด๋ถ€ ํ†ต์‹ ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

4.3.5 ์ž„๋ฒ ๋””๋“œ ํŠธ๋žœ์ŠคํฌํŠธ

Netty๋Š” ํ…Œ์ŠคํŠธ ๋ชฉ์ ์„ ์œ„ํ•ด ์ž„๋ฒ ๋””๋“œ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹ค์ œ ๋„คํŠธ์›Œํฌ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ChannelHandler๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž„๋ฒ ๋””๋“œ ํŠธ๋žœ์ŠคํฌํŠธ์˜ ํŠน์ง•

  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์šฉ๋„: ๋ชจ์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ํ•„์š” ์—†์ด ์‹ค์ œ ํŠธ๋žœ์ŠคํฌํŠธ์™€ ๋™์ผํ•œ API ์ด๋ฒคํŠธ ํ๋ฆ„์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

  • ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์ตœ์ ํ™”: ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ๋„คํŠธ์›Œํฌ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4.4 ํŠธ๋žœ์ŠคํฌํŠธ ์‚ฌ์šฉ ์‚ฌ๋ก€

๊ฐ ํŠธ๋žœ์ŠคํฌํŠธ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • NIO: ๋†’์€ ๋™์‹œ์„ฑ๊ณผ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ์›น ์„œ๋ฒ„ ๋ฐ ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

  • OIO: ๋‹จ์ˆœํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ์˜ ์ด์ฃผ ์‹œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๋กœ์ปฌ ํŠธ๋žœ์ŠคํฌํŠธ: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๋ฐ ๋กœ์ปฌ ํ†ต์‹  ์‹œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

  • ์ž„๋ฒ ๋””๋“œ ํŠธ๋žœ์ŠคํฌํŠธ: ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ๋„คํŠธ์›Œํฌ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•˜์—ฌ ํšจ์œจ์ ์ธ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : Netty์˜ ํŠธ๋žœ์ŠคํฌํŠธ API๋Š” ๋‹ค์–‘ํ•œ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ํ†ต์ผ๋œ ๋ฐฉ์‹์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์—ฌ, ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์— ๋งž๋Š” ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์„ ํƒํ•˜๊ณ  ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

Last updated