netty 귀속 포트 시작 서비스 원본 분석
14577 단어 Netty
netty 귀속 포트 시작 서비스 원본 분석
이 편은 넷티가 포트를 어떻게 연결하고 서비스를 시작하는지 다루고 있다.서비스를 시작하는 과정에서 넷티 각 핵심 구성 요소가 어떻게 넷티의 핵심을 구성하는지 알게 될 것이다
간단한 서버 시작 코드
아래의 코드에 중점을 두다
b.bind(8888).sync();
뒤따라 들어가다
public ChannelFuture bind(int inetPort) {
return bind(new InetSocketAddress(inetPort));
}
포트 번호로 InetSocketAddress를 만들고 계속 따라가세요
public ChannelFuture bind(SocketAddress localAddress) {
validate();
if (localAddress == null) {
throw new NullPointerException("localAddress");
}
return doBind(localAddress);
}
validate () 를 통해 서비스 시작에 필요한 인자를 검증한 다음 DoBind () 를 호출하고 DoBind () 로 들어갑니다.
private ChannelFuture doBind(final SocketAddress localAddress) {
//...
final ChannelFuture regFuture = initAndRegister();
//...
final Channel channel = regFuture.channel();
//...
doBind0(regFuture, channel, localAddress, promise);
//...
return promise;
}
우리는 위의 두 가지 방법, initAndRegister(), 그리고dobind0()에 중점을 두었다.
initAndRegister()
final ChannelFuture initAndRegister() {
Channel channel = null;
// ...
channel = channelFactory.newChannel();
//...
init(channel);
//...
ChannelFuture regFuture = config().group().register(channel);
//...
return regFuture;
}
initAnd Register에서 세 가지 일을 했습니다.new 채널 2.이 채널이 채널을 대상에 등록하기
우리 는 점차 이 세 가지 일 을 분석한다
1. new 하나의 채널
여기 있는 채널은 서비스가 시작될 때 만들어졌기 때문에 일반 Socket 프로그래밍의 ServerSocket과 대응하여 서버가 귀속될 때 지나가는 흐름을 나타낼 수 있습니다
우리는 이 채널이 채널 팩토리 new를 통해 나온 것을 발견했다. 이 채널은 최종적으로 Reflective Channel 팩토리로 호출되었다.newChannel() 메서드
public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
@Override
public T newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
}
반사하는 방식으로 대상을 만듭니다. 이class는 바로 우리가 ServerBootstrap에 전송한NioServerSocketChannel입니다.class
이제 NioServerSocketChannel의 기본 구조 함수에 중심을 둘 수 있습니다.
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
private static ServerSocketChannel newSocket(SelectorProvider provider) {
//...
return provider.openServerSocketChannel();
}
SelectorProvider를 통해openServerSocketChannel () 서버 사이드 채널을 만들고 다음 방법으로 들어갑니다
public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
하나의 서버 채널이 생성되었습니다. 이 세부 사항을 연결할 때, 우리는netty의 몇 가지 기본 구성 요소를 추출합니다. 먼저 다음과 같이 요약합니다.
요약하자면, 사용자 호출 방법Bootstrap.bind(port)의 첫 번째 단계는 반사 방식으로 new의 Nio Server Socket Channel 대상을 반사하고 new의 과정에서 일련의 핵심 구성 요소를 만드는 것이다.
2. init 이 channel
@Override
void init(Channel channel) throws Exception {
/**
1. option attr, options0() attrs0(), options attrs channelConfig channel
*/
final Map, Object> options = options0();
synchronized (options) {
channel.config().setOptions(options);
}
final Map, Object> attrs = attrs0();
synchronized (attrs) {
for (Entry, Object> e: attrs.entrySet()) {
@SuppressWarnings("unchecked")
AttributeKey
3. 이 채널을 어떤 대상에 등록하기
이 단계에서 우리는 다음과 같은 방법을 분석한다
ChannelFuture regFuture = config().group().register(channel);
NioEventLoop에서 register로 호출
@Override
public ChannelFuture register(final ChannelPromise promise) {
ObjectUtil.checkNotNull(promise, "promise");
promise.channel().unsafe().register(this, promise);
return promise;
}
뒤따라 들어가다
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
// ...
AbstractChannel.this.eventLoop = eventLoop;
// ...
register0(promise);
}
EventLoop 이벤트 순환기를 NioServerSocketChannel에 연결한 다음register0 () 을 호출합니다.
private void register0(ChannelPromise promise) {
try {
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
doBind0()
private static void doBind0(
final ChannelFuture regFuture, final Channel channel,
final SocketAddress localAddress, final ChannelPromise promise) {
channel.eventLoop().execute(new Runnable() {
@Override
public void run() {
if (regFuture.isSuccess()) {
channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
} else {
promise.setFailure(regFuture.cause());
}
}
});
}
우리는 DoBind0(...) 방법을 호출할 때 하나의 Runnable를 포장하여 비동기화하는 것을 발견했다. 비동기화task에 대해 우리는 그것의bind 방법에 들어갔다.
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
// ...
boolean wasActive = isActive();
// ...
doBind(localAddress);
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
safeSetSuccess(promise);
}
doBind () 방법
protected void doBind(SocketAddress localAddress) throws Exception {
if (PlatformDependent.javaVersion() >= 7) {
//noinspection Since15
javaChannel().bind(localAddress, config.getBacklog());
} else {
javaChannel().socket().bind(localAddress, config.getBacklog());
}
}
최종적으로 jdk에 있는bind 방법으로 바뀌었습니다. 이 줄 코드가 지나간 후에 정상적인 상황에서 포트의 귀속을 진행했습니다.
총결산
netty 서비스 시작 과정
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[ 네티 인 액션 ] 7. EventLoop와 스레딩 모델또한 애플리케이션의 동시성 요건이나 전반적인 복잡성 때문에 프로젝트의 수명주기 동안 다른 스레드 관련 문제가 발생할 수 있다. 1. io.netty.util.concurrent 패키지는 JDK 패키지인 java.ut...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.