Netty(네티)

Netty 네티의 장점[1] : 블로킹과 논블로킹 변경을 간편하게.

알통몬_ 2017. 12. 19. 10:54
반응형


공감 및 댓글은 포스팅 하는데

 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 

도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 

만들어 나가겠습니다^^

 


블로킹 모드와 논블로킹 모드를 선언하는 관점에서

네티의 장점에 대해서 알아보겠습니다.

소켓의 동작 방식은 블로킹과 논블로킹 두 가지 모드로 나뉘는데요.


블로킹은 요청한 작업이 성공하거나 에러가 나기 전까지는 응답을 돌려주지 않는 것을 말합니다.

논블로킹은 요청한 작업의 성공 여부와는 상관없이 바로 요청한 작업의 결과를 돌려주는 것을 말합니다.


자바에서의 블로킹 모드와 논블로킹 모드의 코드를 보겠습니다.

Blocking.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Blocking {
 
    
    
    public static void main(String[] args) throws Exception {
        
        Blocking server = new Blocking();
        server.run();
    }
    
    private void run() throws Exception {
        ServerSocket server = new ServerSocket(8888);
        System.out.println("[접속 대기 중]");
        
        for(;;) {
            Socket socket = server.accept();
            System.out.println("[클라이언트 연결 됨]");
            
            OutputStream os = socket.getOutputStream();
            InputStream is = socket.getInputStream();
            
            while(true) {
                try {
                    int req = is.read();
                    os.write(req);
                } catch(IOException e) {
                    break;
                }
            }
        }
    }
 
}
cs

for(;;) 대신에 while(true) 를 쓰셔도 됩니다^^


다음은 논블로킹입니다.

NonBlocking.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
 
public class NonBlockingServer {
 
    class Client {
 
        public void send(SelectionKey key){}
        public void receive(SelectionKey key){}
    }
 
    Selector selector; // 넌블로킹의 핵심인 Selector 필드 선언
 
    ServerSocketChannel serverSocketChannel; // 클라이언트 연결 수락하는
                                                // ServerSocketChannel
    List<Client> connections = new Vector<Client>();
 
    void stopServer(){}
    public void accept(SelectionKey key){}
    void start(){
     try {
 
           selector = Selector.open(); // 셀렉터 생성
 
           serverSocketChannel = ServerSocketChannel.open(); // 생성
 
           serverSocketChannel.configureBlocking(false); // 넌블로킹 설정
 
           serverSocketChannel.bind(new InetSocketAddress(5001)); // 포트에 바인딩
 
           serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
 
          } catch (Exception e) {
 
           if(serverSocketChannel.isOpen()) { stopServer(); }
 
           return;// 예외발생시 서버소켓채널이 열려있으면 stop() 호출
 
          } 
 
          
 
          Thread thread = new Thread() {
 
           @Override
 
           public void run() {
 
            while(true) {
 
             try {
 
              int keyCount = selector.select();//작업 처리가 준비된
 
              if(keyCount == 0) { continue; }
 
              Set<SelectionKey> selectedKeys = selector.selectedKeys();
 
                                                   //작업 처리 준비가 된 키를 얻고 Set 컬렉션으로 리턴.
 
              Iterator<SelectionKey> iterator = selectedKeys.iterator();
 
              while (iterator.hasNext()) {
 
                  SelectionKey selectionKey = iterator.next();
 
                  if (selectionKey.isAcceptable()) {//연결 수락 작업일 경우
 
                   accept(selectionKey);
 
                  } else if (selectionKey.isReadable()) {//읽기 작업일 경우
 
                   Client client = (Client)selectionKey.attachment();
 
                   client.receive(selectionKey);
 
                  } else if (selectionKey.isWritable()) {// 쓰기 작업일 경우
 
                   Client client = (Client)selectionKey.attachment();
 
                   client.send(selectionKey);
 
                  }
 
                  iterator.remove();//선택된 키셋에서 처리 완료된
 
              } 
 
             } catch (Exception e) {
 
              if(serverSocketChannel.isOpen()) { stopServer(); }
 
              break;
 
             }
 
            }
 
           }
 
          };
          thread.start();
    }
}
 
cs


블로킹과 논블로킹을 비교해보면 딱 봐도 차이가 많죠?

코드의 길이도 다르고, 구현하는 방법도 차이가 있습니다.


하지만 네티에서는 정말 간단하게, 블로킹과 논블로킹을 거의 같은 코드로 구현할 수 있습니다.

NettyEchoServer를 만들었다고 가정해보겠습니다.

네티 논블로킹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class EchoServer {
    public static void main(String[] args) throws Exception {
        //Thread for accept
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //Thread for I/O
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline cpl = ch.pipeline();
                    cpl.addLast(new EchoServerHandler());
                };
            });
            ChannelFuture f = b.bind(8888).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
cs

다음은

네티 블로킹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class EchoServer {
    public static void main(String[] args) throws Exception {
        //Thread for accept
        EventLoopGroup bossGroup = new OioEventLoopGroup(1);
        //Thread for I/O
        EventLoopGroup workerGroup = new OioEventLoopGroup();
        
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
            .channel(OioServerSocketChannel.class)
            .handler(new LoggingHandler(LogLevel.INFO))
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline cpl = ch.pipeline();
                    cpl.addLast(new EchoServerHandler());
                };
            });
            ChannelFuture f = b.bind(8888).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
cs


두 코드의 차이가 보이시나요?? 

네 바로, NioEventLoopGroup => OioEventLoopGroup로

NioServerSocketChannel => OioServerSocketChannel 로

단 세줄의 코드만 바뀌었는데,

논블로킹 모드에서 블로킹 모드로 변경되었습니다.


어떤가요? 정말 간단하죠?


이상입니다.

감사합니다.


반응형