[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다.
  • 유연하고 확장가능한 이벤트 기반을 둔다.
  • 쓰레드풀이나 단일 쓰레드같은 쓰레드모델을 고급적으로 커스텀할 수 있다.
  • 자원소비가 많지 않으며 불필요한 메모리 복사를 최소화 한다.






[Network/Web Socket]01. 웹 소켓

http://www.tutorialspoint.com/websockets/websockets_quick_guide.htm

http://m.mkexdev.net/98


개요

Handshaking는 두 사람이 악수하는 것으로 정의할 수있는데, 전산에서 의미는 Server와 Client에서 동기상태를 확신하는 처리하 볼 수 있다.

Mobile이나 PC가 Server에게 요청하고, Server는 Client에게 응답하는 Diagram이 Server가 Client와 Handshake한다고 볼 수 있다.


정의

Web Socket의 정의는 Client와 Server 사이에서 양방향 통신(2-way communication)이라 볼 수 있는데, 이는 동시에 Data를 교환하는 것을 말한다.

Web Socket의 요점은 진동시성(?) - True Concurrency와 처리최적화(?) - Optimization of performance로서 더욱더 반응성이 뛰어나고 풍부한 web application을 결과로 나타낸다(?) - more responsive and rich web application.


특징

Web Socket은 표준화되고 있으며, 이 말인 즉슨 Web Server와 Client사이에서 실시간으로 통신하는 것이 이 Protocol의 도움에 의하여 가능하게 된 것이다.(be possible with the help of this protocol)

Web Socket은 Client와 Server사이에 있는 실시간 통신에 대하여 Cross platform 표준으로 변형시키고 있다.

(Cross platform : https://ko.wikipedia.org/wiki/%ED%81%AC%EB%A1%9C%EC%8A%A4_%ED%94%8C%EB%9E%AB%ED%8F%BC)

이 표준은 새로운 종류의 Application이다. 실시간 Web Application을 위한 업무가 이 기술에 의하여 속도를 향상 시킬 수 있다.

Web Socket의 가장 큰 장점은 단일 TCP 연결을 넘는 양방향 통신을 제공하는 것이다.


URL Pattern

기존 HTTP, HTTPS와 같은 Pattern을 정의한다.

Schema :// host : port / server

Ex ) ws :// localhost:8000:aaa.php


양방향 통신에서 사용되는 기술

Polling : Polling은 전송중에 Data가 존재유무에 대한 관계 없이 주기적 요청을 수행하는 방법으로 정의된다. The periodic requests are sent in a synchronous way. Client는 특정 시간 간격에서 Client에게 주기적인 요청을 한다. Server의 응답은 이에 따라 오류나 어떤 자료들을 포함하여 보내게 된다.


Long Polling : Polling 과 유사한 기술을 가졌다. Server 와 Client는 어떤 Data가 전달 받거나(be fetched) timeout이 발생되기 전에 연결상태를 유지한다. 만약에 연결이 끊어지면 Client는 재시작하여 지속적인 요청을 수행할 수 있다. Long Polling 은 기존 Polling과 다를게 없지만 끊임없는 요청이 처리를 늦추게 할 수 있다.(but constant requests may slow down the process.)


Streaming : 실시간 Data 전송에서 최고의 선택으로 여겨진다. Server는 Client와 함께 Data 를 전송받기까지 연결을 유지하는데, 이 경우에는 무기한으로(indefinitely) 연결이 열려있다고 한다. Streaming은 지연시키면서 File size를 늘리는 HTTP Header를 포함하고 있다. 이는 주 문제점(drawback)으로 여겨진다.


AJAX : javascript의 XmlHttpRequest 객체를 기반으로 되어있는 이 기술은 Asynchronous Javascript and XML의 준말이다. XmlHttpRequest 객체는 완전한 web page를 재적재(?) - reload하지 아니하고 javascript를 실행시킨다. Ajax는 단 한 page에서 Data를 주고 받는다.


HTML5 : Web Application을 design하고 개발하기 위한 강력한 framework다. 즉 javascript의 api와 CSS3, Mark-up을 포함하고 있다는 것이다.


필요성

Server는 요청기반으로 생성된 동적 Server Page들을 허용하는 기술로 발전했다(?)(Server technologies advanced which allowed dynamic server pages - pages whose content was generated based on a query.)

언젠가는 더욱더 동적인 web page를 가진 요구사항이 DHTM의 유효성을 이끌 것이다. javascript 덕분에 몇 년 동안 HTTP polling에 의한 page reload를 피하려는 Cross Frame Communication을 보았었다.

그러나 이 해결책이 실제로 Server와 Client의 사이에있는 표준화된 실시간 양방향(Real-time bi-directional) 통신을 제공하진 않았다.

이는 Web Sockets protocol의 필요성을 증대시켰다. 


기능성

web socket이 존재하기 전, 모든 통신은 HTTP에 의존했었다. Web socket은 끊임없는 전양방향 연결의 동적인 흐름을 제어한다. 전양방향은 양 끝단에서 상당히 빠른 속도를 자랑하는 통신이다. 이는 현존하는 protocol의 모든 결점을 극복한 효율성이 있다.


중요성

Web Socket은 독립적인 TCP 기반의 Protocol이지만 순수 TCP연결로 운영중인 다른 Protocol을 지원하는 목적이 있다. 또한 Web Socket은 다른 Protocol이 실행할 수 있는 상위측에 있는 전송계층 이다. Web Socket API는 특정 Protocol을 interpret 할 수 있는 Protocol library들, 즉 Sub protocol을 정의하는 능력을 지원한다. 개발자는 더이상 요청과 응답이라는 HTTP라는 것에서 생각할 필요가 없다. Browser 측의 요구사항은 Web Socket Handshake를 interpret할 수있는 javascript library를 실행하는 것이다. Server 측에서 볼 표준은 Web Socket Gateway에게 영향을 주는것과 TCP 상단에서 실행하는 Protocol library를 사용하는 것이다.


Web Socket은 전형적으로 Web Socket Handshake를 향상된 요청으로 해석함으로서, HTTP나 HTTP server를 경유하여 초기화한다. Web Socket은 HTTP 환경에서 상호 보완적인 추가물일 수 있고, Web 기능성을 추가하는 필수적 기반 구조를 제공할 수 있다. 또한 client와 server 사이에서 양방향으로 data를 흐르게 하는 전 양방향 protocol에 의존한다. 


연결과정

Client는 web socket handshake라고 알려진 과정을 통해 연결을 설립한다.

이 과정은 Client가 server에게 정기적인 HTTP요청을 보내면서 시작한다.

향상된 Header가 요청된다. 이 요청에서 server는 web socket 연결을 위한 요청이라 알림을 받는다.

ws라 언급한 scheme는 web socket의 URL로 표기하는데 이는 HTTP와 동등한 web socket 연결을 보안하는데 있어 사용되기도 한다.


실행

Web socket은 web만이 아니라 mobile에서도 주 역할을 차지하고 있다. 

Web socket은 말 그대로 web과 관련이 있다. Web browser를 위한 다수의 기술을 구성하는 web은 mobile이나 PC 등을 포함한 수많은 장치들에서 방대한 연결 platform이다.

Web socket이라는 Protocol의 목적은 다음과 같은 주요점에서 여겨진다.

단일 연결을 통한 전 양방향을 사용해서 네트워크 지연(network latency)과 체증의 불필요함을 줄이는 것.

Streaming through proxies and firewalls, with the support of upstream and downstream communication simultaneously.


Event와 Action

Server와 Client사이에서 통신을 위한 연결을 초기화 해야된다. 이러한 연결을 초기화 하기 위해서는 local이나 원격 Server를 가진 URL javascrip 객체 생성이 필수다.

1
var socket = new WebSocket(“ ws://echo.websocket.org ”);
cs


Event

Web socket API에 대한 주 Event는 아래와 같다.

Open, Message, Close, Error

각 Event는 onopen, onmessage, onclose, onerror와 같은 함수들을 실행하면서 동작된다. 또한 이런 함수들은 addEventListener라는 method에 의해 실행되는 것이다.


Open

Client와 Server 사이에서 연결이 성립되면 open event가 Web socket instance로부터 종료된다. 이를 양측간에 초기 handshake라 한다.


Message

server가 data를 보낼때 발생된다. server가 client에게 전송하는 Message는 이진 Data, plain text, image들이 포함되어있다. Data가 보내질때마다 onmessage 함수는 종료된다.


Close

통신이 끝날때 발생한다. onclose로 통신이 끝나면 message는 전송이 불가능하다. 


Error

통신중 문제가 있으면 발생한다. 

'Network > Web Socket' 카테고리의 다른 글

[Network/Web Socket]01. 웹 소켓  (0) 2016.08.30

[Network/Http]04. DBCP

DBCP(DB Connection Pool)


http://gangzzang.tistory.com/entry/%ED%86%B0%EC%BA%A3Tomcat-%EC%BB%A4%EB%84%A5%EC%85%98%ED%92%80DBCP-%EC%84%A4%EC%A0%95


http://holiclove.tistory.com/entry/%ED%86%B0%EC%BC%93-DB-connection-%EA%B4%80%EB%A0%A8-Serverxmlwebxml-%EC%84%A4%EC%A0%95

'Network > Http' 카테고리의 다른 글

[Network/Http]04. DBCP  (0) 2016.08.01
[Network/Http]03. Servlet, HTTP Protocol  (0) 2016.07.04
[Network/Http]02. Web, Tomcat  (0) 2016.06.22
[Network/Http]01. CS관계와 자원위치.  (0) 2016.06.22

[Transfer Protocol/Theory]01. TCP/IP


- TCP/IP

컴퓨터의 데이터 통신을 위하여 제작된 인터넷 표준 프로토콜이다.

데이터의 분할을 오류가 발생하지 않을 정도로 동작하여 전송하고

받은 정보를 본래의 정보로 변환하는 것을 약속한 것.


TCP(Transmission Control Protocol)는

전송 데이터를 일정 단위로 분할하고 포장하는 것과 관련된 규약이다.

데이터의 흐름과 정확성을 관리하는 역할까지 한다.

그만큼 신뢰성이 보장되고, 

데이터의 전송을 위한 연결을 생성하는 연결지향 규약이다.


IP(Internet Protocol)

데이터를 주고 받는 것과 관련된 규약이다.

패킷을 목적지까지 전송하는 것을 관리한다.

[패킷(Packet)은 네트워크를 통해 전송하기 쉽도록 자른 데이터의 전송단위다.]

노드(통신장치)마다 주소가 있을테고, IP는 그 노드의 주소를 구분해서 찾아간다.

(보통 192.168.0.0과 같은 IP 주소는 식별성이 어렵기 때문에 www.naver.com과 같은 Domain Name 서비스를 사용한다.)


 - 특징

컴퓨터간에 통신중 TCP/IP를 선택한 이유는 

하드웨어, 운영체제와 같은 플랫폼에 독립적이라는 특징을 보유하고 있기 때문이다.


신뢰성

앞에서 언급하듯, 자체적 오류를 처리해서, 

전송의 순서를 교정하고 그에 대한 데이터고 교정하는 특징이있다.


연결지향

서로간에 데이터를 송수신하는 노드의 입장에서 볼 때,

연결지향은 데이터의 전송을 위한 선로(Session)을 만든다는 의미다. 

설령 데이터의 전송이 이루어지지 않음에도 불구하고, 재전송을 요구한다.


 - 동작원리

OSI 7계층이과 다른 용어들의 이해가 요구되므로 차후 학습후 작성예정.

'Network > Theory' 카테고리의 다른 글

[Transfer Protocol/Theory]01. TCP/IP  (0) 2016.07.31

+ Recent posts

티스토리 툴바