[Network/Netty]07. Netty 구축을 위한 beans(3) - ChannelPipeline

(출처 : http://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html
           
http://ash84.net/2013/03/08/exs4j-netty-channelpipeline--ec-97-90--eb-8c-80-ed-95-9c--ec-9d-b4-ed-95-b4/)


1. ChannelPipeline
    
public abstract interface ChannelPipline extends Iterable<Map.Entry<String, ChannelHandler>>
    ChannelHandler들을 모아놓은 일련의 목록.
    
이벤트가 발생됨에 따라 내부에 등록된 ChannelHandler들을 동작하기 위한 관리자라고 볼 수 있다.


2. 동작원리

    • Preview
      입출력 이벤트는 ChannelInoundHander, ChannelOutboundHandler에 의하여 다루어진다.
      또한 그 이벤트는 ChannelHandlerContext에서 정의된 이벤트 전달 method를 호출하여 근접한 핸들러에 전달된다.
    • Inbound event
      외부로부터 무언가를 받았다는 의미인 만큼 inbound handler의 최초 시점은 Netty의 내부에 있는 thread이다.
      부르기 편하게 그냥 네티라 하겠음. 네티가 외부에서 받은 어떤 데이터를 읽었을 것이다.(SocketChannel.read(...))
      pipeline에서 inbound handler를 등록했다면, 등록된 순서대로 데이터를 처리하고 다른 inbound handler에 전달한다.
      등록된 모든 inbound event가 끝나게 되면 inbound event는 종료되고 log에 남게된다.
    • Outbound event
      최초 시점은 가장 마지막에 등록된 outbound handler다.
      자신이 외부에 무언가를 보낸다는 의미이기 때문에,
      inbound event와 달리 등록된 outbound event를 모두 거치고
      네티에서 마무리를 짓게된다.(SocketChannel.write(...))

      두 이벤트를 등록한 아래의 예제를 볼 때, 진행되는 순서는 125543이다.
      (5번의 경우 Inbound, Outbound를 모두 상속받은 bean이라 본다.)
1
2
3
4
5
6
 ChannelPipeline p = ...;
 p.addLast("1"new InboundHandlerA());
 p.addLast("2"new InboundHandlerB());
 p.addLast("3"new OutboundHandlerA());
 p.addLast("4"new OutboundHandlerB());
 p.addLast("5"new InboundOutboundHandlerX());
cs


3. 실제 서버 구현
    아래 예제에서, 
다른 내용은 다 무시하고 실제 pipeline에 등록된 내용에 집중한다.
    ByteArrayDecoder, ByteArrayEncoder는 네티에서 제공해주는 bean이고
    요청과 응답에 대한 데이터들을 
byte array로 암복호화 해주는 역할을 담당한다.

    
그러니까 등록된 handler의 로직을 대략적으로 본다면

    1. 요청 데이터 유입 - Netty
    2. byte array로 복호화 - ByteArrayDecoder
      (참고로 들어오는 모든 데이터들은 ByteBuf로 추상화 되어있음.)
    3. 필자가 작성한 EchoServerHandler 로직 수행. SimpleChannelInoundHandler를 상속받음.
    4. byte array로 암호화 - ByteArrayEncoder
    5. 요청에 대한 응답 - Netty
    6. handler로직 수행 끝.


 4. Why SimpleChannelInoundHandler?
       설명하기 앞서 해당 bean은 ChannelInboundHandler를 구현받았고 가장 추상적인 bean은 ChannelHandler다.
       
ChannelInboundHandler에서 override된 method들을 통해 이벤트들을 처리하게 될 것이다.


       주의깊게 볼 method는 channelRead0다.
       다른 bean에서도 있을지 모르겠지만 channelRead0는 SimpleChannelInoundHandler에서만 작성되어있다.
       
channelRead의 내용을 분석하면
       SimpleChannelInoundHandler의 channelRead는 
       해당 매개변수 중에 요청받은 데이터인 Object msg를 SimpleChannelInoundHandler에서 상속하였을때
       지정한 Generic과 일치하는가를 따져본 후에 
channelRead0을 진행한다.
       그렇지 아니하면 오류가 발생되어 log에 WARN이 출력된다.
       
그러나 SimpleChannelInoundHandler의 channelRead0는 요청받은 데이터의 유형이
       
애초부터 지정한 Generic을 매개변수의 유형으로 두고있다.
       따
라서 channelRead에서 진행되는 일련의 작업들을 할 필요가 없다.

        아무튼 SimpleChannelInoundHandler는 요청받은 데이터인 msg에 대한 유형 검사 작업을 할 필요가 없기 때문에
        
읽을때의 작업을 수월하게 진행 할 수 있다.

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
public static void main(String[] args) {
        
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try{
            // 서버 부트스트랩 생성
            ServerBootstrap b = new ServerBootstrap();
            
            // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 서버 회선 설정 시작. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        
            // 이벤트루프 설정
            b.group(bossGroup, workerGroup)
            // 채널입출력방식 설정
            .channel(NioServerSocketChannel.class)
            
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 서버부트스트랩의 초기화가 진행될때. 시작 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // 최초 클라이언트로부터의 연결이 들어오는 큐에 대하여 100개까지 지정.
            .option(ChannelOption.SO_BACKLOG, 100)
            // 이벤트 핸들러 설정 - 로그핸들러로 지정.
            .handler(new LoggingHandler(LogLevel.INFO))
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 서버부트스트랩의 초기화가 진행될때. 끄읕 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            
            
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 클라이언트로부터 연결이 완료된 후. 시작 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // 새로 연결된 채널과 이벤트 핸들러 설정
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel paramC) throws Exception {
                    paramC.pipeline().addLast("1"new ByteArrayDecoder());
                    paramC.pipeline().addLast("2"new EchoServerHandler());
                    paramC.pipeline().addLast("3"new ByteArrayEncoder());
                }
            })
            // 세션 해제 여부 감지.
            .childOption(ChannelOption.SO_KEEPALIVE, true);
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 클라이언트로부터 연결이 완료된 후. 끄읕 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            
            // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 서버 회선 설정 끄읕. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            
            ChannelFuture f = b.bind(PORT).sync();
            f.channel().closeFuture().sync();
            
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
cs




[Netwok/Netty]06. Netty 구축을 위한 beans(1) - ServerBootstrap

(출처 : http://javafactory.tistory.com/1382)

1. Beans

    • public abstract class AbstractBootstrap<Generic........>
      bootstrab의 사전적 의미는 한 번 시작하면 알아서 진행되는 일련의 과정을 말한다.
      이 추상클래스는 헬퍼클래스로서 서버든 클라이언트든 이를 상속시켜주어 실제 소켓을 구현하게 도움을 준다.
      특히 단어의 특성에 따라 method chaining이 가능하다.
      기동을 하기위한 전체적인 일종의 틀 혹은 컨테이너.
    • public class ServerBootStrap
      extends AbstractBootstrap<ServerBootstrap, ServerChannel>
      실제 서버를 구현하는 부트스트랩.
      클라이언트의 연결을 수락하고 연결된 클라이언트 소켓에 대하여 입출력을 처리하는 두 개의 쓰레드 그룹을 관리한다.
      하나의 쓰레드 그룹으로도 지정할 수는 있지만, 원활한 병행처리를 위하여 두 개의 그룹을 생성하기를 권장한다.

    • public class BootStrap extends AbstractBootstrap<Bootstrap, ServerChannel>
      실제 클라이언트를 구현하는 부트스트랩. connect라는 method를 통해 해당 주소에 연결한다.
2. Methods
    • public ServerBootstrap group
      (EventLoopGroup parentGroup, EventLoopGroup, childGroup)
      이벤트 루프 설정.
      클라이언트의 연결을 수락하고 연결된 클라이언트 소켓에 대하여 입출력을 처리하는 두 개의 쓰레드 그룹을 관리한다.
      하나의 쓰레드 그룹으로도 지정할 수는 있지만, 원활한 병행처리를 위하여 두 개의 그룹을 생성하기를 권장한다.
    • public B channel(Class<? extends C> channelClass)
      '해당 서버 부트스트랩에 지정할 채널에 대하여 어떤 방식으로 통신할 것인가'를 지정한다.
      부모클래스의 AbstractBootstrap을 상속받고 있고 개발자가 원하는 채널을 지정할 수 있다.
      지금은 nio만 할 것이므로 NioServerSocketChannel.class를 사용한다.
    • public <T> B option(ChannelOption<T> option, T value)
      AbstractBootstrap으로 부터 상속받았다.
      상속받은 method들은(option, handler) 최초 서버 기동에 대한 초기설정에 불과하다.
      최초 클라이언트로부터 연결에 대한, 서버 자신의 채널(혹은 소켓)옵션을 지정한다.
      이 종류는 ChannelOption에서 확인이 가능하다. 

      참고로 매개변수 SO_BACKLOG, 100의 의미는 
      클라이언트로부터의 연결이 들어오는 큐에 대하여 몇 개까지 지정할 수 있는가를 말한다.

    • public B handler(ChannelHandler handler)
      본 method를 통해 해당 서버소켓(혹은 채널)에서 발생 되는 이벤트들을 담당한다.
      LoggingHandler는 서버에서 발생되는 모든 이벤트들을 Log로 출력한다.
      본 Bean을 들여다보면 
      ChannelInboundHandler를 상속받고 ChannelOutboundHandler를 구현받고 있다.
      이 말인 즉슨 서버입장에서 당발, 타발에 대한 이벤트들을 Log로 출력한다는 의미로 볼 수 있다.

    • public ServerBootstrap childHander(ChannelHander handler)
      ServerBootstrap에서 구현된 child method(childHandler, childOption)이다.
      클라이언트로 부터 연결이 들어 올 때, 본 method를 통해서 해당 클라이언트와의 발생되는 이벤트들을 관리하게 된다.
      매개변수는 ChannelInitializer를 작성함으로서, 새로 연결된 Channel과 환경설정을 지정해준다.
      대부분 ChannelPipeline을 이용하여 handler들을 계속 추가한다.
      실제 이벤트가 발생되면 어떤 동작을 취하는지는 본 method를 통해 작성할 수 있다.

    • public <T> ServerBootstrap childOption
      (ChannelOption<T> childOption, T value)
      클라이언트로 부터 연결이 온 후에 해당 소켓(혹은 채널)에 대한 옵션을 지정한다.
      SO_KEEPALIVE의 의미는 해당 클라이언트와 연결한 세션에 대하여 종료여부를 감지하는 것을 말한다.
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
public static void main(String[] args) {
        
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        
        try{
            // 서버 부트스트랩 생성
            ServerBootstrap b = new ServerBootstrap();
            
            // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 서버 회선 설정 시작. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
        
            // 이벤트루프 설정
            b.group(bossGroup, workerGroup)
            // 채널입출력방식 설정
            .channel(NioServerSocketChannel.class)
            
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 서버부트스트랩의 초기화가 진행될때. 시작 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // 최초 클라이언트로부터의 연결이 들어오는 큐에 대하여 100개까지 지정.
            .option(ChannelOption.SO_BACKLOG, 100)
            // 이벤트 핸들러 설정 - 로그핸들러로 지정.
            .handler(new LoggingHandler(LogLevel.INFO))
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 서버부트스트랩의 초기화가 진행될때. 끄읕 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            
            
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 클라이언트로부터 연결이 완료된 후. 시작 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            // 새로 연결된 채널과 이벤트 핸들러 설정
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel paramC) throws Exception {
                    paramC.pipeline().addLast(new ByteArrayDecoder());
                    paramC.pipeline().addLast(new EchoServerHandler());
                    paramC.pipeline().addLast(new ByteArrayEncoder());
                }
            })
            // 세션 해제 여부 감지.
            .childOption(ChannelOption.SO_KEEPALIVE, true);
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 클라이언트로부터 연결이 완료된 후. 끄읕 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            
            // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 서버 회선 설정 끄읕. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            
            ChannelFuture f = b.bind(PORT).sync();
            f.channel().closeFuture().sync();
            
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
cs




[Netwok/Netty]05. Netty 구축을 위한 beans(1) - Group

1. public absctract interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor>
    
데이터를 주고 받는 이벤트들의 생명주기를 관리한다.
    다시 말하자면 데이터를 주고 받는 그 이벤트들이 일종의 쓰레드라 볼 수 있는데, 이러한 쓰레드들을 관리하는 스케쥴러와 같다.

2. public abstract interface EventLoopGroup extends EventExecutorGroup
    
서로 다른 종류들을 가진 전송 이벤트들의 추상적 모델.

3. public class NioEventLoopGroup extends MultithreadEventLoopGroup
    
NIO라는 전송이벤트로 입출력 동작을 다루는 Multithread EventLoop. 



[Netwok/Netty]04. 사전에 파악할 용어

(출처 : https://shortstories.gitbooks.io/studybook/content/c8fc_c694_d2b9_c9d5.html
           
http://clairdelunes.tistory.com/62
           
http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/)
대체적인 뜻만 파악하고 차후 하나씩 분석한다.


1. Sync 통신
    
특정 서비스를 요청하면 응답이 올 때 까지 기다리는 통신. 
    혹은 응답을 받아서 작업 완료 여부까지 요청하는 작업까지 진행한다.
    직관적 흐름을 추적할 수 있다.

2. Async 통신
    
특정 서비스를 요청하면 응답이 올 때 까지 기다리지 않고 다른 작업을 하고 있으면서, 완료여부에는 관심없는 통신.
    
메모리 자원의 효율적 활용이 가능. Future, Callback과 같은 패턴이 있음.

3. Blocking Socket
    
특정 서비스를 요청하면 요청받은 자가 작업이 모두 종료될 때까지 요청자에게 작업 제어권을 넘겨주지 않고 대기하는 상태.

4. Non-Blocking Sokect
    
특정 서비스를 요청한 직후 바로 응답을 받아서 남아있는 작업을 진행할 수 있는 제어권이 있는 Socket.
    
Sync/Async 는 '요청하는 자가 작업 완료에 대하여 신경을 쓰는가' 가 주 관심사이면
    
Blocking/Non-Blocking은 '요청하는 자가 요청 직후 바로 제어권을 바로 잡을 수 있는가' 가 주 관심사다.

5. Event Driven Network Programming
    
소켓을 이벤트의 주체로 하는 네트워크 프로그래밍. 데이터들을 소켓에 전달하는 핸들러를 이용한다.
    
기능별로 분리된 논리에 의하여 명확성이 있고 재사용성이 증가되며 오류의 부담이 완화되어있다.

6. Channel
    
일종의 소켓으로서 기존 Java의 Socket의 복잡함을 단순하게 작업하는 API들을 제공한다.

7. EventLoop
    
데이터가 교환하는 이벤트가 발생되어, 이를 처리하는 일련의 작업 순서를 생명주기라 부르겠다.
    EventLoop는 이러한 생명주기를 관리한다. 
이러한 EventLoop들이의 집합을 EventLoopGroup라 부른다.
    
EventLoop는 데이터 환이 진행되는동안 (생명주기가 돌고 있는동안) 에는 하나의 작업(Thread) 만을 담당한다.
    
EventLoop에서 처리되는 모든 입출력 동작은 해당 Thread에서 처리된다.
    
Channel은 EventLoop에 등록할 수 있다.

8. ChannelFuture
    Async 통신방식 특성에 따라 요청에 대한 응답이 바로 오지 않을 수 있다.
    따라서 그 결과를 확인하는 방법이 요구되는데, ChannelFuture는 이러한 실행에 대한 결과를 파악할 수 있도록 해준다.

9. OutBound, 당발
    
상대방이 아닌 본 Channel이 상대방에게 보낸다는 형용사.

10. InBound, 타발
    
상대방으로부터 본 Channel에게 보낸다는 형용사.

11. Handler
    당발, 타발 전송 할 때의 데이터를 관리한다.

12. PipleLine
    
Handler들의 Chainning하는 컨테이너를 제공하고 당발, 타발 이벤트를 전달한다.

13. Decoder
    
전문을 수신할 때 데이터를 변환한다.
    
당발 전문이 올 때, Byte에서 개발자가 지정한 다른 형태로 변환하는 작업을 한다.

14. Encoder
    
전문을 송신할 때 데이터를 변환한다.
    
타발 전문을 보낼 때, 해당 형태에서 Byte로 변환하는 작업을 한다.

15. Bootstrap
    
서버, 클라이언트를 구축한다. 사전적 의미는 한 번 시작하면 알아서 진행되는 일련의 과정이다.
    이 뜻에 따라  method chaning이 가능하다. 
일종의 기동을 하기위한 전체적인 틀 혹은 컨테이너.


[Netwok/Netty]03. ByteBuffer VS ByteBuf - ByteBuf

(출처 : https://netty.io/4.0/api/io/netty/buffer/ByteBuf.html)


1. 차이점

ByteBuffer는 capacity, limit, potion로 데이터를 읽고 썼다.
읽든 쓰든 position이 변경되고, flip을 통해 읽기와 쓰기를 하는데 있어 계산을 하면서 개발해야 한다. 
또한 capacity는 한번 지정하면 변경이 불가하기에 새로 객체를 생성해야된다.
그러니까 setCapacity(int capacity)같은 method가 없다는 의미.
게다가 capacity를 넘는 데이터를 입력하면 BufferOverflowException발생한다.

Bytebuf는 capacity, read index, write index만을 두고 있기 때문에
따로 flip이라는 동작을 하지 않아도 읽고 쓰는 작업에 편의성이 있다.
capacity를 변경하는 method를 지원한다. capacity를 넘는 데이터를 입력하면 2 제곱 단위로 증가후에 입력한다.

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
public class DiffernceBoth {
 
    public static void main(String[] args) {
        
        ByteBuffer byteBuffer = ByteBuffer.allocate(13);
        // java.nio.HeapByteBuffer[pos=0 lim=13 cap=13]
        System.out.println(byteBuffer);
        
        byteBuffer = ByteBuffer.allocate(14);
        // java.nio.HeapByteBuffer[pos=0 lim=13 cap=14]
        System.out.println(byteBuffer);
        
//        BufferOverflowException
//        byteBuffer.put("012345678912341".getBytes());
        
        
        ByteBuf byteBuf = Unpooled.buffer(13);
        // (ridx: 0, widx: 0, cap: 13)
        System.out.println(byteBuf);
        
        byteBuf.capacity(14);
        // (ridx: 0, widx: 0, cap: 14)
        System.out.println(byteBuf);
        
        // write 59 bytes
        byteBuf.writeBytes("This is byte array longer than previous capacity of byteBuf".getBytes());
        // (ridx: 0, widx: 59, cap: 64)
        System.out.println(byteBuf);
        
        byteBuf.capacity(14);
        // This is byte a
        System.out.println(byteBuf.toString(Charset.defaultCharset()));
        // (ridx: 0, widx: 14, cap: 14)
        System.out.println(byteBuf);
        
        
    }
 
}
cs


2. 객체생성
    
Unpooled.buffer(int initialCapacity)라는 method를 통해 생성하길 권장한다.
    실제로 생성자는 있지만 override해야 되는 method들이 많기 때문에 비효율적이다.
    (예제 소스를 쓰자니 overrided method가 워낙 많아서 생략)


3. read, write, clear
    ByteBuffer와 다른점은 없으나 읽을수 있는 byte와 쓸 수 있는 byte를 명확하게 보여주기 때문에 편의성이 있다.
    그리고 안에 내용들을 모두 초기화 하는 clear가 있다.

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
public class ReadWrite {
 
    public static void main(String[] args) {
        
        ByteBuf byteBuf = Unpooled.buffer(12);
        // read : 0, write : 12
        System.out.print("read : " + byteBuf.readableBytes());
        System.out.println(", write : " + byteBuf.writableBytes());
 
        System.out.println("write 11 bytes");
        byteBuf.writeBytes("Hello world".getBytes());
        // read : 11, write : 1
        System.out.print("read : " + byteBuf.readableBytes());
        System.out.println(", write : " + byteBuf.writableBytes());
        
        System.out.println("read 4 bytes");
        byteBuf.readInt();
        // read : 7, write : 1
        System.out.print("read : " + byteBuf.readableBytes());
        System.out.println(", write : " +byteBuf.writableBytes());
        
        System.out.println("clear");
        byteBuf.clear();
        // read : 0, write : 12
        System.out.print("read : " + byteBuf.readableBytes());
        System.out.println(", write : " +byteBuf.writableBytes());        
        
        
    }
 
}
cs



[Netwok/Netty]02. ByteBuffer VS ByteBuf - ByteBuffer

(출처 : http://aoruqjfu.fun25.co.kr/index.php/post/561)

  1. Buffer
    사전적 의미는 완충을 말한다.
    컴퓨터 시스템의 어떤 장치에서 다른 장치로 전송을 할 때에, 
    일시적으로 그 데이터를 보관하는 일종의 메모리 영역이다.
    buffering이라 함은 buffer를 채우는 동작을 일컷는 말로서 유사어로 Queue가 있다.

  2. ByteBuffer
    Java NIO에서 제공되는 Buffer다.
    NIO의 Buffer는 다양한 자료형들을 관리하고있으며 내부의 배열상태를 관리한다.(ByteBuffer, CharBuffer, IntBuffer...)

  3. Buffer의 field
    • capacity
      Buffer에 저장할 수 있는 최대 크기. 한 번 지정하면 변경이 불가능하다.

    • position
      Buffer를 읽고 있는 현재 위치, Buffer를 쓰고 있는 현재 위치를 말한다.
      초기값은 0이고 읽고 쓸 때마다 증가된다. limit와 capacity보다 작거나 같다.

    • limit
      읽고 쓸 수 있는 공간의 최대치를 말한다. limit는 변경이가능하며 capacity보다는 크게 지정될 수 없다.

  4. Buffer의 method
    • public static ByteBuffer allocate(int capacity)
      capacity를 사용자가 직접 지정하고 position은 초기값으로 지정한다.
      limit는 capacity와 동일하게 입력된다. ByteBuffer를 새로 생성할 때 사용되며 JVM Heap에 생성한다.
      ByteBuffer의 하위 빈 HeapByteBuffer를 생성하는 셈이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Allocate {
 
    public static void main(String[] args) {
        
        ByteBuffer byteBuffer = ByteBuffer.allocate(11);
 
        // java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
        // 11 Bytes Put
        byte[] source = "Hello world".getBytes(); 
        byteBuffer.put(source);
 
        // java.nio.HeapByteBuffer[pos=1 lim=11 cap=11]
        System.out.println(byteBuffer);
    }
 
}
cs



    • public static ByteBuffer allocateDireact(int capacity)
      capacity를 사용자가 직접 지정하고 position은 초기값으로 지정한다.
      limit는 capacity와 동일하게 입력된다. ByteBuffer를 새로 생성할 때 사용되며 JVM Heap에 생성한다. 
      ByteBuffer의 하위 빈 MappedByteBuffer의 하위 빈 DirectByteBuffer를 생성하는 셈이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class AllocateDirect {
 
    public static void main(String[] args) {
        
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(11);
        
        // java.nio.DirectByteBuffer[pos=0 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        // true
        System.out.println(byteBuffer.isDirect());
 
    }
 
}
cs



    • public static ByteBuffer wrap(byte[] array)
      배열을 이용해서 객체를 생성한다. 이는 HeapByteBuffer를 이용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Wrap {
 
    public static void main(String[] args) {
        
        byte[] array = {123456789100};
        ByteBuffer byteBuffer = ByteBuffer.wrap(array);
 
        // java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
        System.out.print(byteBuffer);
        
        // false
        System.out.println(byteBuffer.isDirect());
        
    }
 
}
cs



    • public ByteBuffer put(byte b)
      현재 position을 기준으로 하여 byte를 write한다. 이후 position은 1 증가.
    • public byte get()
      현재 position을 기준으로 하여 byte를 read한다. 이후 position은 1 증가.
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
public class ReadWrite {
 
    public static void main(String[] args) {
        
        ByteBuffer byteBuffer = ByteBuffer.allocate(11);
 
        // java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
        
        byteBuffer.put((byte1);
        System.out.println("write 1 Byte");
        
        // java.nio.HeapByteBuffer[pos=1 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
        
        byteBuffer.get();            
        System.out.println("read 1 Byte");
        
        // java.nio.HeapByteBuffer[pos=2 lim=11 cap=11]
        System.out.println(byteBuffer);
        
    }
 
}
cs


    • public final Buffer rewind()
      position을 0으로 이동
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
public class Rewind {
 
    public static void main(String[] args) {
        
        ByteBuffer byteBuffer = ByteBuffer.allocate(11);
 
        // java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
        byteBuffer.put((byte10);
        System.out.println("write 1 Byte");
        // java.nio.HeapByteBuffer[pos=1 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
        byteBuffer.put((byte20);                            
        System.out.println("write 1 Byte");
        // java.nio.HeapByteBuffer[pos=2 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
        byteBuffer.rewind();
        System.out.println("rewind");
        // java.nio.HeapByteBuffer[pos=0 lim=11 cap=11]
        System.out.println(byteBuffer);
 
        
        byteBuffer.get();
        System.out.println("read 1 Byte");
        // java.nio.HeapByteBuffer[pos=1 lim=11 cap=11]
        System.out.println(byteBuffer);
        
        
    }
 
}
cs


    • public final Buffer flip()
      limit를 현재 position으로 두고, 현재 position을 0으로 변경
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Flip {
 
    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(11);
 
        System.out.println(byteBuffer);
 
        byteBuffer.put((byte10);
        byteBuffer.put((byte20);
        byteBuffer.put((byte30);
        byteBuffer.put((byte40);
        System.out.println("write 4 Bytes");
        
        System.out.println(byteBuffer);
 
        System.out.println("flip");
        byteBuffer.flip();
 
        // 11 : 0 : 4
        System.out.println(byteBuffer);
    }
 
}
 
cs


[Netwok/Netty]01. OverView

(출처 : https://netty.io/)

  • 비동기형태의 이벤트 기반 네트워크 애플리케이션 프레임워크로서 지속적으로 유지가 가능하고 높은 성능을 가진 서버와 클라이언트간에 빠른 개발을 위한 목적을 두고있다.
  • 빠르고 쉬운 네트워크 애플리케이션 개발이 가능하며 단순하고 TCP, UDP같은 스트림형 네트워크 프로그램을 단순화 하였다.
  • 블록킹과 넌블록킹 소켓 같은 다양한 전송 타입을 통합한 API다.
  • 유연하고 확장가능한 이벤트 기반을 둔다.
  • 쓰레드풀이나 단일 쓰레드같은 쓰레드모델을 고급적으로 커스텀할 수 있다.
  • 자원소비가 많지 않으며 불필요한 메모리 복사를 최소화 한다.






+ Recent posts