넷티 가이드 클래스 ServerBootstrap의 각 방법의 역할에 대해 0부터 배우기

21228 단어 Netty

netty 공식 사용자 안내서


이것은 넷티 공식적인 사용자 안내서입니다. 독자 여러분께서 먼저 읽고 상술한 문서에 따라 한 번 조작해 주십시오.

ServerBootstrap 시작 프로세스에 대한 간단한 설명


이번 학습의 넷티 환경 버전은 4.1.45이다.문서에 따라 서버(Discard Server), 응답 서버(Echo Server), 시간 서버(Time Serve)를 버립니다.우리는 그들이 모두 ServerBootstrap이라는 종류를 사용했다는 것을 발견할 수 있다. 이 종류는 각종 자원을 통합하고 서버를 만드는 종류이다. 그들이 만든 논리는 기본적으로 비슷하지만 각각의handler는 다르다. 이것은 서버 기능이 다른 근본적인 원인이다.
DiscardServer를 예로 들 수 있습니다.
public class DiscardServer {
    
    private int port;
    
    public DiscardServer(int port) {
        this.port = port;
    }
    
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); //  Acceptor 
        EventLoopGroup workerGroup = new NioEventLoopGroup(); //  
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class) // (3) channel 
             .childHandler(new ChannelInitializer<SocketChannel>() { // (4) worker channel 
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
             .option(ChannelOption.SO_BACKLOG, 128)          // (5) option ,SO_BACKLOG , , 
             .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) 
    
            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7) , 
    
            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    
    public static void main(String[] args) throws Exception {
        int port = 8080;
        if (args.length > 0) {
            port = Integer.parseInt(args[0]);
        }

        new DiscardServer(port).run();
    }
}

위의 7단계 이전의 작업은 모두 서버를 설정하는 행위입니다. 서버의 수신 연결을 지정한 루트 그룹, 연결된 루트 그룹,channel의 유형,option 매개 변수, 각각channel이 어떤handler를 거쳐야 하는지를 처리합니다.마지막으로bind 함수에서 서버를 시작합니다.
 //io.netty.bootstrap.ServerBootstrap#group	
  public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
        return this;
    }
    //io.netty.bootstrap.AbstractBootstrap#group
  public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = ObjectUtil.checkNotNull(childGroup, "childGroup");
        return this;
    }

그룹을 예로 들면, 단지 두 그룹의 값을 부여한 가이드 클래스에서 시작할 때 사용합니다.
bind야말로 핵심 코드, io.netty.bootstrap.Abstract Bootstrap #doBind는 일하는 방법입니다. 그 중에서 init And Register () 에서 bossgroup을 초기화합니다.뒤에 포트가 연결되어 서버가 시작되었습니다.넷티 가이드 클래스에서 사용하는 각 방법이 어떤 작용을 하는지 알려주고 싶어서 원본을 아래로 세밀하게 채우지 않습니다.
private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {
            // Registration future is almost always fulfilled already, but just in case it's not.
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                        // IllegalStateException once we try to access the EventLoop of the Channel.
                        promise.setFailure(cause);
                    } else {
                        // Registration was successful, so set the correct executor to use.
                        // See https://github.com/netty/netty/issues/2586
                        promise.registered();

                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }

네트워크 프로그래밍과 연계하여 각 방법의 작용을 이해하다


우리 인터넷 상호작용의 몇 가지 관건을 대조해 보자.우선 연결을 만듭니다. (이것은 bossGroup이 완성하고 그 내부는 select에 사용됩니다. 연결이 들어오면 들어오는 채널을workerGroup의select에 등록하고 그 다음에 읽기와 쓰기는workerGroup이 완성합니다.)
2. 그리고 서버는 연결된 정보에 따라 업무 처리를 한다.반환 데이터 포함 (이 단계는 위의childHandler에 대응하는pipeline의 초기화 작업이 있습니다. 즉, 클라이언트가 보낸 메시지는channel로 봉인되고 이 pipeline에서 각종handler의 처리를 거칩니다. 우선 네트워크 전송은 바이트 흐름의 형식이기 때문에 먼저 디코딩을 해서 우리가 처리할 수 있는 문자가 되고 이 문자에 따라 업무 처리를 해야 합니다. 업무 처리도 그 중의 하나입니다.)
3. 연결 해제
socket 전송을 직접 처리할 수 있는 바이트 흐름이라는 특성을 바탕으로 우리는 자신의 응용층 프로토콜을 실현하고handler를 통해 전송된 정보를 해석한 다음에 미리 정의된 프로토콜에 따라 처리할 수 있다.netty는 http 서버를 개발할 수 있을 뿐만 아니라 많은 우수한 소스 프레임워크가 netty를 바탕으로 하고 자신의 프로토콜, 예를 들어dubbo를 실현했다.

좋은 웹페이지 즐겨찾기