1. EventLoopGroup Interface (io.netty.channel)
- netty 에는 EventLoopGroup 이라는 인터페이스가 있으며 EventGroup 은 여러개의 EventLoop를 갖고있는 풀방식을 취합니다.
이 중에서, nio을 처리하는 NioEventLoopGroup 을 이용해서 간단한 예제를 구현해보겠습니다.
@Slf4j
public class EventLoopGroupStudy {
public static void main(String[] args) {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
for(int i = 0 ; i < 100 ; i++) {
int x = i;
eventLoopGroup.next().execute(() -> log.info("execute loopGroup {}", x));
}
}
}
22:04:21.753 [nioEventLoopGroup-2-10] INFO EventLoopGroupStudy - execute loopGroup 9
22:04:21.753 [nioEventLoopGroup-2-10] INFO EventLoopGroupStudy - execute loopGroup 33
22:04:21.753 [nioEventLoopGroup-2-10] INFO EventLoopGroupStudy - execute loopGroup 57
22:04:21.754 [nioEventLoopGroup-2-10] INFO EventLoopGroupStudy - execute loopGroup 81
22:04:21.755 [nioEventLoopGroup-2-9] INFO EventLoopGroupStudy - execute loopGroup 8
22:04:21.755 [nioEventLoopGroup-2-9] INFO EventLoopGroupStudy - execute loopGroup 32....
비동기적인 프로그래밍을 한 것처럼, 해당 결과는 뒤죽박죽의 순서로 결과가 찍힙니다.
- 이는 EventLoopGroup 에서 하나의 Runnable task 를 수행하면 EventLoop에 할당한 뒤에 수행을 맡기기 때문입니다. (새로운 쓰레드에 위임하는 방식과 같습니다.)
NioEventLoopGroup 이 NioServerSocketChannel 을 갖고있으며 맨 앞단에서 Selector 과 비슷한 역할을 합니다.
- ※ 내부적으로 EventLoop가 Selector를 사용합니다.
- ※ NioServerSocketChannel 은 java 의 ServerSocketChannel 과 유사하며, 비동기적으로 처리하는 netty 에서 제공하는 클래스입니다.
코드로보면 아래와 같습니다.
- ChannelFuture 은 비동기적인 결과를 받는 Java의 Future 과 유사한 기능을합니다.
- 아래의 코드에서는 bind 에 대한 결과를 받아 정상적으로 수행됐다면 bind Completed 메세지가 출력됩니다.
- 해당 코드는 종료되지않고 연결을 기다리고있습니다.
@Slf4j
public class EventLoopGroupStudy {
public static void main(String[] args) {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
final NioServerSocketChannel channel = new NioServerSocketChannel();
eventLoopGroup.register(channel);
final ChannelFuture bind = channel.bind(new InetSocketAddress(8080));
bind.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
log.info("bind completed : {}", future);
}
});
}
}
bind completed : [id: 0x729bde16, L:/0:0:0:0:0:0:0:0:8080]
위의 결과에서 보다시피, ChannelFuture 에는 바인딩된 정보가 들어있고, 이를 통해 연결된 채널의 정보를 가져올 수 있습니다. (여기서는 NioServerSocketChannel 을 연결했으므로 NioServerSocketChannel 이겠죠)
2. PipeLine
channel 에는 pipeLine 을 추가할 수 있습니다.
- channel 에 어떤 데이터가 왔을때 어떻게 수행하라고 명시할 수 있습니다.
- pipeline 에는 여러개의 Handler를 추가할 수 있으며, 순차적으로 진행됩니다.
- ChannelInboundHandler, ChannelOutBoundHandler 를 공부해보세요!
ChannelInboundHandlerAdapter 를 통해서 channelRead 이벤트가 발생하는 경우 출력해보는 코드를 작성해보겠습니다.
- 코드가 많이 헷갈릴 수 있으나
- operationComplete(ChannelFuture future) -> 바인드가 성공한 경우
- future.channel().pipeline().addLast(ChannelHandler...) -> 바인드가 성공한 채널의 파이프라인에 핸들러를 등록한다.
@Slf4j
public class EventLoopGroupStudy {
public static void main(String[] args) {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
final NioServerSocketChannel channel = new NioServerSocketChannel();
eventLoopGroup.register(channel);
final ChannelFuture bind = channel.bind(new InetSocketAddress(8080));
bind.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
log.info("{}", future.channel());
future.channel().pipeline()
.addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
final Channel channel = (Channel) msg;
log.info("channel : {}", channel);
super.channelRead(ctx, msg);
}
});
}
});
}
}
위의 코드를 수행한뒤에 1. Java Channel 에서 만든 클라이언트로 연결을 시도하면 아래와같이 출력됩니다.
- 8181 포트의 클라이언트가 8080 쪽으로 정상적으로 연결됐습니다.
- EventLoop 가 로그를 출력하였으므로, 응답을 보내거나 하는 부분은 EventLoop 가 도맡아 수행하게되며, 비동기적으로 수행하게됩니다.
- EventLoop 에 등록된 NioSocketChannel은 해당 EventLoop 가 도맡아 끝까지 처리합니다.
22:55:39.501 [nioEventLoopGroup-2-1] INFO EventLoopGroupStudy - channel : [id: 0xa3ed8d0c, L:/127.0.0.1:8080 - R:/127.0.0.1:8181]
'netty' 카테고리의 다른 글
3. BootStrap (0) | 2021.04.13 |
---|---|
1. Java Channel (0) | 2021.04.10 |