"Original" https://github.com/code4craft/netty-learning/blob/master/posts/ch3-pipeline.md
Channel is the core of understanding and using Netty. The channel involves a lot of content, here I use the introduction method of the way. In this article, we mainly introduce the pipeline implementation mechanism in the channel section. In order to avoid boring, borrow "dream space" of "dream" concept, I hope you like.
A Dream: Channel implementation overview
In Netty, Channel
it is the carrier of communication, which is ChannelHandler
responsible for the logic processing in the channel.
So ChannelPipeline
what is it? I think it can be understood as a Channelhandler container: A channel contains a channelpipeline, and all Channelhandler are registered in Channelpipeline and organized sequentially.
In Netty, ChannelEvent
is the carrier of the data or the state, for example the data of the transmission corresponds MessageEvent
, the change of the state corresponds ChannelStateEvent
. When the channel is operated, a channelevent is generated and sent to the ChannelPipeline
. Channelpipeline will select a channelhandler for processing. After this channelhandler is processed, new channelevent may be generated and transferred to the next Channelhandler.
For example, a data is initially a MessageEvent
, it comes with a raw binary message that is not decoded ChannelBuffer
, and then a handler decodes it into a data object, generates a new one MessageEvent
, and passes it to the next process.
Here, you can see that the core process of the channel is ChannelPipeline
in. So we go into the deep dream of channelpipeline, and look at its concrete realization.
Two-story dream: The main course of Channelpipeline
Netty's channelpipeline consists of two lines: upstream and downstream. Upstream corresponds to the upstream, received the message, the passive state change, all belong to upstream. Downstream the corresponding downlink, the message sent, the active state change, all belong to downstream. The ChannelPipeline
interface contains two important methods: sendUpstream(ChannelEvent e)
and sendDownstream(ChannelEvent e)
, respectively, corresponds to upstream and downstream.
Corresponding, the channelhandler contained in the Channelpipeline also contains two categories: ChannelUpstreamHandler
and ChannelDownstreamHandler
. The handler of each line is independent of one another. They are simple enough to contain only one method: ChannelUpstreamHandler.handleUpstream
and ChannelDownstreamHandler.handleDownstream
.
Netty Official Javadoc There is a picture (in the ChannelPipeline
interface), the very image of this mechanism (I made a little change to the original, plus ChannelSink
, because I think this part of the understanding of the code process will be some help):
What do you call ChannelSink
it? Channelsink contains an important method ChannelSink.eventSunk
that can accept arbitrary channelevent. "Sink" means "sinking", then "Channelsink" seems to be understood as "where the channel sinks"? In fact, it does so, or it can be said: "At the end of the almighty handler." When I first read about it, it was a bit confusing and it was a lot easier to understand. only downstream included ChannelSink
, here are some important operations such as establishing connections, binding ports, and so on. Why Uploadstream no Channelsink? I can only think, on the one hand, is not in line with the meaning of "sink", on the other hand, there is nothing to do with it!
Here's a note: in a "flow", a "stream" that ChannelEvent
does not take the initiative is generated by all handler, but by an explicit invocation of the previous handler ChannelPipeline.sendUp(Down)stream
, and handed over to the next handler processing . That is, each handler receives a channelevent, and after processing is finished, if it needs to continue processing, then it needs to invoke sendUp(Down)stream
a new event to be initiated. If it no longer initiates the event, then the process ends, even if there is still handler behind it. This mechanism guarantees maximum flexibility and, of course, has stricter requirements for the sequencing of handler.
By the way, in Netty 3.x, this mechanism causes a large number of Channelevent objects to be created, so the Netty 4.x version has been improved. In the Finagle framework practice of Twitter, it is mentioned that upgrading from Netty 3.x to Netty 4.x can significantly reduce GC overhead. Interested to see this article: Https://blog.twitter.com/2013/netty-4-at-twitter-reduced-gc-overhead
Below we from the code level to do in-depth analysis of what is happening in this part, which involves some details, the need to open the project source code, compared to see, will be more fruitful.
Three-storey dream: deep inside channelpipeline internal defaultchannelpipeline structure
ChannelPipeline
The main implementation code is in the DefaultChannelPipeline
class. Make a list of the main fields of Defaultchannelpipeline:
PublicClassDefaultchannelpipelineImplementsChannelpipeline{PrivateVolatileChannelChannel;PrivateVolatileChannelsinksinkprivate volatile defaultchannelhandlercontext Headprivate volatile defaultchannelhandlercontext Tailprivate final map<String< Span class= "O", defaultchannelhandlercontext> name2ctx = new hashmap<string defaultchannelhandlercontext> (4 /span>
This interface needs to be introduced here ChannelHandlerContext
. As the name implies, Channelhandlercontext preserves the contextual information associated with Netty handler. What we have here DefaultChannelHandlerContext
is a package of the right ChannelHandler
one. An DefaultChannelHandlerContext
internal, in addition to a containing one ChannelHandler
, also holds "next" and "prev" two pointers, thus forming a doubly linked list.
So, in DefaultChannelPipeline
, we see a reference to the right DefaultChannelHandlerContext
, not ChannelHandler
a direct reference to it. This includes two references for "head" and "tail", pointing to the head and tail of the linked list, respectively. Name2ctx, however, is a map of defaultchannelhandlercontext users indexed by name, which is primarily used when deleting or adding Channelhandler by name.
Sendupstream and Senddownstream
As mentioned earlier, ChannelPipeline
two important methods of the interface are: sendUpstream(ChannelEvent e)
and sendDownstream(ChannelEvent e)
. The initiation of all events is based on these two methods. Channels
classes have a series fireChannelBound
of such fireXXXX
methods, in fact, are the two methods of facade packaging.
Let's look at the implementation of these two methods. First Look at Sendupstream (some simplification of the code, preserving the main logic):
PublicvoidSendupstream(ChanneleventE){DefaultchannelhandlercontextHead=Getactualupstreamcontext(This.Head);Head.GetHandler().Handleupstream(Head,E);}PrivateDefaultchannelhandlercontextGetactualupstreamcontext(DefaultchannelhandlercontextAt) {defaultchannelhandlercontext realCtx = ctxwhile (! Realctx.{realctx = Realctx.if (realctx == null {return null} } return realctx /span>
The
Here finally calls the Channelupstreamhandler.handleupstream
to handle this channelevent. Interestingly, we do not see any "move handler backwards one" operation, but we can not always use the same handler to deal with AH? In fact, we are more commonly used by the Channelhandlercontext.handleupstream
method (Implementation is Defaultchannelhandlercontext.sendupstream
method):
Sendupstream(egetactualupstreamcontext(this. Nextdefaultchannelpipeline. This. Sendupstream(nexte}
As you can see, the method is still called here ChannelPipeline.sendUpstream
, but it will move the handler pointer back .
Let's look at the following DefaultChannelHandlerContext.sendDownstream
:
PublicvoidSenddownstream(ChanneleventE){DefaultchannelhandlercontextPrev=Getactualdownstreamcontext(This.Prev);If(Prev==Null){Try{Getsink().Eventsunk (defaultchannelpipeline. Thise} catch (throwable t ) {notifyhandlerexception (e< Span class= "O", t} } else {defaultchannelpipeline< Span class= "O". this. (preve} } /span>
It doesn't seem to be the same with Sendupstream, huh? Here are two points: first, when you reach the end, as in Dream Two, you call channelsink for processing, and the pointer moves forward , so we know:
Upstreamhandler is carried out from the back, and Downstreamhandler is executed from the back forward. you need to pay attention to the order when you add it in Channelpipeline!
There are some mechanisms in defaultchannelpipeline, such as adding/removing/replacing handler, and ChannelPipelineFactory
so on, a better understanding, not to elaborate.
Back to reality: Pipeline solves the problem
Well, in-depth analysis of the code, a little dizzy, we go back to the beginning of the place, to think, Netty pipeline mechanism to solve what problem?
I think there are at least two points:
One is to provide Channelhandler programming model, based on Channelhandler development business logic, basically do not need to care about the network communication aspects, focus on coding/decoding/logic processing on it. Handler is also a more convenient development model, which is useful in many frameworks.
The second is to realize the so-called "Universal asynchronous API". This is also a feature that Netty officially advertised. Both Oio and NiO know that the two sets of API styles are vastly different, and that moving from one to the other costs a lot. Even NiO, there is a large gap between asynchronous and synchronous programming. The Netty shielded the API differences between OIO and NIO, providing an external interface through the channel and connecting it through Channelpipeline, so it's easy to replace.
Having cleared up the mainstream of channelpipeline, we have figured out the approximate structure of the channel section. But here, we still have a connection to the specific how to deal with no concept, the next article, we will analyze, in the Netty, the shortcut how to deal with the establishment of connections, data transmission these things.
Ps:pipeline This part dragged for two months, finally finished. Writing in the middle is slow, write a high quality (at least think it!). Article is not easy, but still do not bear this part of this rotten tail. Some of the best articles are referenced in the middle, and some applications have been developed using Netty. After this kind of article, still want to concentrate time to write intact.
Resources:
- Sink HTTP://EN.WIKIPEDIA.ORG/WIKI/SINK_ (computing)
"Turn" netty that thing. (iii) pipeline in the channel