Get through the network source code series seven worker group registration NioSocketChannel
worker group registration NioSocketChannel
First, fill in a relatively easy to understand registration chart. Here, temporarily register all new channels to an event cycle of the same worker group, which is actually registered by load balancing:
The registration is the same as the boss group, but at this time, the parameter is NioSocketChannel type, and one will be selected from the NioEventLoop of the worker group to register:
It should be noted that the Unsafe in it is actually of the type NioSocketChannel.NioSocketChannelUnsafe, which inherits from NioByteUnsafe. At a glance, it is byte related, so it is used to read and write data:
We see two unsafe subclasses. The one above is used by NioServerSocketChannel, and the one below is used by NioSocketChannel. In fact, they are only different in read:
register is the same as the method of the parent class. The same as the previous NioServerSocketChannel registration is to submit the registration task and start the thread. You can see that the thread of the worker group is started:
After that, the worker group's thread performs the registration task, such as selector registration SocketChannel instance:
Then, when we do pipeline. Invokehandleraddedifneed(); the handlerAdded method of our custom childHandler will be executed, and the initChannel method of ChannelInitializer will be executed
Then the corresponding handlerAdded, channelRegistered, channelActive methods are started. That is, the processor is added, registered, and activated.
After the task is completed, it enters the select block.
Read message
Once the established connection is established and the message is sent, it will be processed. As before, a series of methods such as processSelectedKeys will be called. Until the read method, the main method is the doReadBytes(byteBuf) method:
public final void read() { final ChannelConfig config = config(); if (shouldBreakReadReady(config)) { clearReadPending(); return; } final ChannelPipeline pipeline = pipeline(); final ByteBufAllocator allocator = config.getAllocator();//Byte buffer allocator final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle(); allocHandle.reset(config); ByteBuf byteBuf = null; boolean close = false; try { do { byteBuf = allocHandle.allocate(allocator); allocHandle.lastBytesRead(doReadBytes(byteBuf));//Here is the key, read issue if (allocHandle.lastBytesRead() <= 0) { // nothing was read. release the buffer. byteBuf.release(); byteBuf = null; close = allocHandle.lastBytesRead() < 0; if (close) { // There is nothing left to read as we received an EOF. readPending = false; } break; } allocHandle.incMessagesRead(1); readPending = false; pipeline.fireChannelRead(byteBuf);//Deliver read event byteBuf = null; } while (allocHandle.continueReading()); allocHandle.readComplete(); pipeline.fireChannelReadComplete(); if (close) { closeOnRead(pipeline); } } catch (Throwable t) { handleReadException(pipeline, byteBuf, t, close, allocHandle); } finally { // See https://github.com/netty/netty/issues/2254 if (!readPending && !config.isAutoRead()) { removeReadOp(); } } }
doReadBytes
@Override protected int doReadBytes(ByteBuf byteBuf) throws Exception { final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();//Get allocation processor allocHandle.attemptedBytesRead(byteBuf.writableBytes());//Set writable bytes return byteBuf.writeBytes(javaChannel(), allocHandle.attemptedBytesRead());//Read the data of the channel and write the byte buffer }
writeBytes
Writing data to the buffer is the key:
@Override public int writeBytes(ScatteringByteChannel in, int length) throws IOException { ensureWritable(length); int writtenBytes = setBytes(writerIndex, in, length); if (writtenBytes > 0) { writerIndex += writtenBytes; } return writtenBytes; }
setBytes
in.read is that the channel reads the data in the socket buffer from the bottom to the byte buffer:
@Override public final int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { try { return in.read(internalNioBuffer(index, length)); } catch (ClosedChannelException ignored) { return -1; } }
internalNioBuffer
This method actually returns ByteBuffer, that is to say, the bottom layer encapsulates ByteBuffer:
@Override public final ByteBuffer internalNioBuffer(int index, int length) { checkIndex(index, length); return _internalNioBuffer(index, length, false); }
_internalNioBuffer
As expected:
final ByteBuffer _internalNioBuffer(int index, int length, boolean duplicate) { index = idx(index); ByteBuffer buffer = duplicate ? newInternalNioBuffer(memory) : internalNioBuffer(); buffer.limit(index + length).position(index); return buffer; }
In addition, DirectByteBuffer is a direct buffer, which reduces the data copy from kernel to user space once:
allocHandle.lastBytesRead(doReadBytes(byteBuf))
Then we will make some records. For example, this time we read 11 bytes. Why 11 bytes? Because my client sent a hello world, we will see:
pipeline.fireChannelRead(byteBuf)
Next is to transfer the buffer data to the pipeline and let the processor handle it. As mentioned in the previous article, how to transfer it is not much to say, but what should be noted here is:
If it is a reference counting tired heart, it will be encapsulated:
We can see that all byte buffers customized by netty are of reference count type:
So in the end, the touch(java.lang.Object) of AbstractReferenceCountedByteBuf is executed, seemingly unchanged:
Finally, it is passed to my customized processor and read out:
My client is sent by NIO:
summary
Basically, your process is almost the same as the one in the previous article, but there is a little difference in reading data. Now that we know the general process, we will continue to look at the details later. In fact, I'm talking about the general process, but it's very important to be clear about the skeleton. Otherwise, I'll drill into the details at the beginning, and I won't be able to get out.
Well, I'm here today. I hope it will be helpful for learning and understanding. God can't see it. Just for his own learning and understanding, his ability is limited. Please forgive me.