Netty4.x原始碼分析
一、基本元素整理
Bootstrap:Netty的啟動類
NioEventLoopGroup:負責處理事件,通過執行緒監聽selector處理讀、寫、連線
ChannelFuture:Netty大量使用了Future模式,既能同步也能非同步獲取結果
NioSocketChannel:所有Socket封裝成Channel進行讀寫
ChannelPipeline、ChannelHandler:採用責任鏈模式,ChannelPipeline將多個ChannelHandler串聯起來執行,ChannelHandler負責處理資料
StringDecoder、StringEncoder:負責字串的編解碼,是ChannelHandler的具體實現
二、呼叫示例
Bootstrap b = new Bootstrap();
b.group(new NioEventLoopGroup());
b.channel(NioSocketChannel.class);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline ph = ch.pipeline();
ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
ph.addLast("decoder", new StringDecoder());
ph.addLast("encoder", new StringEncoder());
ph.addLast("handler", new HelloClientHandler()); // 客戶端的邏輯
}
});
b.connect("127.0.0.1", 8000).addListener(new GenericFutureListener<ChannelFuture>() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if(!future.isSuccess()){
future.cause().printStackTrace();
return;
}
Channel ch =future.channel();
final String str = "Hello Netty2";
ch.writeAndFlush(str + "\r\n").addListener(new GenericFutureListener<ChannelFuture>() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if(!future.isSuccess()){
future.cause().printStackTrace();
return;
}
System.out.println("客戶端傳送資料:" + str);
}
});
}
});
三、connect分析
3.1、呼叫javaChannel().register(eventLoop().unwrappedSelector(), 0, this);註冊selector
3.2、呼叫boolean connected = SocketUtils.connect(javaChannel(), remoteAddress);建立連線
3.3、通過ChannelFuture返回結果
public ChannelFuture connect(String inetHost, int inetPort)
->return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
->return doResolveAndConnect(remoteAddress, config.localAddress());
->final ChannelFuture regFuture = initAndRegister(); --【Bootstrap】
->channel = channelFactory.newChannel(); --channelFactory是ReflectiveChannelFactory 通過反射建立channel【AbstractBootstrap】
->init(channel);
->ChannelFuture regFuture = config().group().register(channel); --group是NioEventLoopGroup【AbstractBootstrapConfig】
->return next().register(channel); --EventLoop是NioEventLoop【MultithreadEventLoopGroup】
->... 最終呼叫javaChannel
->selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this); --【AbstractNioChannel】
->return regFuture; --regFuture是DefaultChannelPromise
->final Channel channel = regFuture.channel(); --【Bootstrap】
->final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
->regFuture.addListener( --regFuture是DefaultChannelPromise
@Override
public void operationComplete(ChannelFuture future) --【Bootstrap】
->promise.registered(); --【Bootstrap】
->registered = true;
->doResolveAndConnect0(channel, remoteAddress, localAddress, promise); --【Bootstrap】
->final EventLoop eventLoop = channel.eventLoop(); --【Bootstrap】
->final AddressResolver<SocketAddress> resolver = this.resolver.getResolver(eventLoop);
->final Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress); --【Bootstrap】
->resolveFuture.addListener(new FutureListener<SocketAddress>() {
@Override
public void operationComplete(Future<SocketAddress> future) throws Exception { --丟到非同步執行緒請求,防止阻塞
->doConnect(future.getNow(), localAddress, promise);
->final Channel channel = connectPromise.channel();
->channel.eventLoop().execute(new Runnable() { --eventLoop是NioEventLoop,繼承SingleThreadEventExecutor【Bootstrap】
->public void run() {
->channel.connect(remoteAddress, localAddress, connectPromise); --【Bootstrap】
->boolean connected = SocketUtils.connect(javaChannel(), remoteAddress); --javaChannel是SocketChannel
->return socketChannel.connect(remoteAddress);
四、write分析
4.1、客戶端呼叫this.addTask(task);將msg封裝成task丟到EventLoop中非同步執行
4.2、非同步執行緒呼叫this.write(this.ctx, this.msg, this.promise);往伺服器傳送資料
4.3、通過ChannelFuture返回傳送結果
ChannelFuture writeAndFlush(Object msg)
->return this.pipeline.writeAndFlush(msg); //AbstractChannel
->return this.tail.writeAndFlush(msg); //DefaultChannelPipeline
->return this.writeAndFlush(msg, this.newPromise()); //AbstractChannelHandlerContext
->this.write(msg, true, promise); //AbstractChannelHandlerContext
->AbstractChannelHandlerContext next = this.findContextOutbound();
->do while(!ctx.outbound)
->ctx = ctx.prev;
->return ctx;
->task = AbstractChannelHandlerContext.WriteAndFlushTask.newInstance(next, m, promise); //AbstractChannelHandlerContext
->init(task, ctx, msg, promise);
->task.ctx = ctx;
->task.msg = msg;
->ctx.pipeline.incrementPendingOutboundBytes((long)task.size);
->return task;
->safeExecute(executor, (Runnable)task, promise, m); //AbstractChannelHandlerContext
->executor.execute(runnable);
->this.startThread();
->this.addTask(task);
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {
abstract static class AbstractWriteTask implements Runnable {
this.write(this.ctx, this.msg, this.promise);
->super.write(ctx, msg, promise); //WriteAndFlushTask
->ctx.invokeWrite(msg, promise); //AbstractWriteTask
->this.invokeWrite0(msg, promise); //AbstractChannelHandlerContext
->((ChannelOutboundHandler)this.handler()).write(this, msg, promise); //AbstractChannelHandlerContext
->this.encode(ctx, cast, out); //MessageToMessageEncoder
->out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), this.charset)); //StringEncoder
->ctx.write(out.get(0), promise); //MessageToMessageEncoder
->this.write(msg, false, promise); //AbstractChannelHandlerContext
->AbstractChannelHandlerContext next = this.findContextOutbound(); //AbstractChannelHandlerContext
->next.invokeWrite(m, promise); //AbstractChannelHandlerContext
->this.invokeWrite0(msg, promise); //AbstractChannelHandlerContext
->((ChannelOutboundHandler)this.handler()).write(this, msg, promise); //AbstractChannelHandlerContext
->this.unsafe.write(msg, promise); //DefaultChannelPipeline.HeadContext
->outboundBuffer.addMessage(msg, size, promise);
->ctx.invokeFlush(); //WriteAndFlushTask
->this.invokeFlush0(); //AbstractChannelHandlerContext
->((ChannelOutboundHandler)this.handler()).flush(this); //AbstractChannelHandlerContext
->ctx.flush(); //ChannelOutboundHandlerAdapter
->next.invokeFlush(); //AbstractChannelHandlerContext
->this.invokeFlush0(); //AbstractChannelHandlerContext
->((ChannelOutboundHandler)this.handler()).flush(this);
->this.unsafe.flush();
->this.flush0(); //AbstractChannel
->AbstractChannel.this.doWrite(outboundBuffer); //AbstractChannel
->while(true)
->java.nio.channels.SocketChannel ch = this.javaChannel();
->int localWrittenBytes = ch.write(nioBuffer);
}
}
五、read分析
5.1、NioEventLoop通過迴圈監聽SelectionKey.OP_READ,通過NioSocketChannel接收訊息
5.2、ChannelHandler在非同步執行緒中接收並處理資料
public final class NioEventLoop extends SingleThreadEventLoop {
protected void run() {
for (;;) {
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.SELECT:
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
}
processSelectedKeys();
->processSelectedKeysOptimized();
->final Object a = k.attachment();
->processSelectedKey(k, (AbstractNioChannel) a);
->final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
->if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0)
->unsafe.read();
}
}
}
public abstract class AbstractNioByteChannel extends AbstractNioChannel {
protected class NioByteUnsafe extends AbstractNioUnsafe {
public final void read() {
final ChannelPipeline pipeline = pipeline();
do {
pipeline.fireChannelRead(byteBuf);
->AbstractChannelHandlerContext.invokeChannelRead(head, msg); //DefaultChannelPipeline
->
} while (allocHandle.continueReading());
}
}
}
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
->((ChannelInboundHandler) handler()).channelRead(this, msg);
->ctx.fireChannelRead(msg); //DefaultChannelPipeline.HeadContext
->invokeChannelRead(findContextInbound(), msg);
->next.invokeChannelRead(m); //迴圈呼叫next.invokeChannelRead(m)
->((ChannelInboundHandler) handler()).channelRead(this, msg);
->ByteBuf data = (ByteBuf) msg; //ByteToMessageDecoder
->callDecode(ctx, cumulation, out); //ByteToMessageDecoder
->while (in.isReadable()) //ByteToMessageDecoder
->fireChannelRead(ctx, out, outSize); //ByteToMessageDecoder
->fireChannelRead(ctx, (CodecOutputList) msgs, numElements);
->for (int i = 0; i < numElements; i ++)
->ctx.fireChannelRead(msgs.getUnsafe(i)); //ByteToMessageDecoder
->invokeChannelRead(findContextInbound(), msg); //AbstractChannelHandlerContext
->next.invokeChannelRead(m); //AbstractChannelHandlerContext
->((ChannelInboundHandler) handler()).channelRead(this, msg);
->decode(ctx, cast, out); //MessageToMessageDecoder
->out.add(msg.toString(charset)); //StringDecoder
->ctx.fireChannelRead(out.getUnsafe(i));
->invokeChannelRead(findContextInbound(), msg);
->next.invokeChannelRead(m); //AbstractChannelHandlerContext
->((ChannelInboundHandler) handler()).channelRead(this, msg);
->channelRead0(ctx, imsg); //SimpleChannelInboundHandler
->System.out.println("客戶端接受的訊息: " + msg); //HelloClientHandler
} else {
executor.execute(new Runnable() {
public void run() {
next.invokeChannelRead(m);
}
})
}
}
}
相關文章
- Retrofit原始碼分析三 原始碼分析原始碼
- 集合原始碼分析[2]-AbstractList 原始碼分析原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- 集合原始碼分析[1]-Collection 原始碼分析原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- 以太坊原始碼分析(36)ethdb原始碼分析原始碼
- 以太坊原始碼分析(38)event原始碼分析原始碼
- 以太坊原始碼分析(41)hashimoto原始碼分析原始碼
- 以太坊原始碼分析(43)node原始碼分析原始碼
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- 以太坊原始碼分析(52)trie原始碼分析原始碼
- 深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析MyBatis原始碼SQLSessionUI
- k8s client-go原始碼分析 informer原始碼分析(6)-Indexer原始碼分析K8SclientGo原始碼ORMIndex
- k8s client-go原始碼分析 informer原始碼分析(4)-DeltaFIFO原始碼分析K8SclientGo原始碼ORM
- 5.2 spring5原始碼--spring AOP原始碼分析三---切面原始碼分析Spring原始碼
- Spring原始碼分析——搭建spring原始碼Spring原始碼
- 以太坊原始碼分析(35)eth-fetcher原始碼分析原始碼
- 以太坊原始碼分析(20)core-bloombits原始碼分析原始碼OOM
- 以太坊原始碼分析(24)core-state原始碼分析原始碼
- 以太坊原始碼分析(29)core-vm原始碼分析原始碼
- 以太坊原始碼分析(34)eth-downloader原始碼分析原始碼
- 精盡MyBatis原始碼分析 - MyBatis-Spring 原始碼分析MyBatis原始碼Spring
- k8s client-go原始碼分析 informer原始碼分析(5)-Controller&Processor原始碼分析K8SclientGo原始碼ORMController
- SocketServer 原始碼分析Server原始碼
- React 原始碼分析React原始碼
- Dialog原始碼分析原始碼
- Axios原始碼分析iOS原始碼
- [原始碼分析]ArrayList原始碼
- CAS原始碼分析原始碼
- preact原始碼分析React原始碼
- httprouter 原始碼分析HTTP原始碼
- retrofit 原始碼分析原始碼
- LeakCanary 原始碼分析原始碼
- redux原始碼分析Redux原始碼
- Hyperapp原始碼分析APP原始碼
- DialogFragment原始碼分析Fragment原始碼