Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How Netty binds ports and starts services

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article introduces the knowledge of "how Netty binds ports and starts services". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Server starts DEMO

Let's start with a simple server to start `DEMO`. The following is a standard `Netty` server code.

Public final class NettyServer {public static void main (String [] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup (); EventLoopGroup workerGroup = new NioEventLoopGroup (); try {ServerBootstrap serverBootstrap = new ServerBootstrap () ServerBootstrap.group (bossGroup, workerGroup) .channel (NioServerSocketChannel.class) .childHandler (new ChannelInitializer () {@ Overridepublic void initChannel (SocketChannel channel) {ChannelPipeline channelPipeline = channel.pipeline (); channelPipeline.addLast ("decoder", new StringDecoder ()) ChannelPipeline.addLast ("encoder", new StringEncoder ()); channelPipeline.addLast ("handler", new ServerHandler ());}}); ChannelFuture channelFuture = serverBootstrap.bind (8888). Sync (); channelFuture.channel (). CloseFuture (). Sync () } finally {bossGroup.shutdownGracefully (); workerGroup.shutdownGracefully ();} br

Note: ServerBootstrap.childHandler () is used to specify the read and write processing logic for processing new connection data, while ServerBootstrap also provides handler () to specify some logic during server startup, which is usually not needed.

The code of `ServerHandler` is as follows:

Public class ServerHandler extends ChannelInboundHandlerAdapter {@ Override public void channelActive (ChannelHandlerContext ctx) {System.out.println ("channelActive");} @ Override public void channelRegistered (ChannelHandlerContext ctx) {System.out.println ("channelRegistered");} @ Override public void handlerAdded (ChannelHandlerContext ctx) {System.out.println ("handlerAdded");} @ Override public void channelReadComplete (ChannelHandlerContext ctx) throws Exception {System.out.println ("channelReadComplete") } @ Override public void channelInactive (ChannelHandlerContext ctx) throws Exception {System.out.println ("channelInactive");} @ Override public void channelRead (final ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println ("service receive msg:" + msg);}} br

When a new connection is connected, the console prints out

ReStructuredTexthandlerAddedchannelRegisteredchannelActivebr

But when a new message is received, the console prints out

ReStructuredTextservice receive msg:xxxchannelReadCompletebr

This paper mainly analyzes the startup process of the server, and the reading of new messages accessed by new connections will be described in the following chapters.

Analysis of server startup source code

`ServerBootstrap` is a bind class designed for developers to use. The core code entry is `ServerBootstrap`. The code is as follows

Public ChannelFuture bind (int inetPort) {return bind (new InetSocketAddress (inetPort));} / / create a `InetSocketAddress` through the port number, and then continue to call the overloaded `InetSocketAddress` (SocketAddress localAddress) {/ /. Return doBind (localAddress);} br

Due to the limited space of the blog, some robust branches will skip `/ /.`, robust branches will not affect the understanding of the main process of `Netty`.

The `Netty` server starts up and finally calls the `Netty` method. The code is as follows

Private ChannelFuture doBind (final SocketAddress localAddress) {/ /... final ChannelFuture regFuture = initAndRegister (); /... final Channel channel = regFuture.channel (); / /. DoBind0 (regFuture, channel, localAddress, promise); / /... return promise;br

In `initAndRegister () `, we focus on the two core methods, `initAndRegister ()` and `doBind0 () `.

Server `Channel` creation

Final ChannelFuture initAndRegister () {Channel channel = null;// New Channel channel = channelFactory.newChannel (); / / initialize Channelinit (channel); / / transfer this Channel Register to an object ChannelFuture regFuture = config () .group () .register (channel); return regFuture;} br

`Channel` is one of the core concepts of `Netty`. It is the main body of `Netty` network communication. It is responsible for network communication, registration, data operation and other functions with the peer.

The creation of `Channel` is completed by `Channel`. Next, we trace when `channelFactory` is initialized. We finally find that it is in this function to trace back layer by layer.

Public B channel (Class, Object > e: attrs.entrySet ()) {AttributeKey key = (AttributeKey) e.getKey (); channel.attr (key) .set (e.getValue ());}} ChannelPipeline p = channel.pipeline (); final EventLoopGroup currentChildGroup = childGroup;final ChannelHandler currentChildHandler = childHandler;final Entry, Object > [] currentChildAttrs Synchronized (childOptions) {/ / set options currentChildOptions for new access to channel = childOptions.entrySet (). ToArray (newOptionArray (childOptions.size ());} synchronized (childAttrs) {/ / set attrs currentChildAttrs = childAttrs.entrySet (). ToArray (newAttrArray (childAttrs.size ();} p.addLast (new ChannelInitializer () {@ Overridepublic void initChannel (Channel ch) throws Exception {final ChannelPipeline pipeline = ch.pipeline ()) / / set handler to pipeline / / the handler () here returns the value ChannelHandler handler = config.handler () set by .handler (); if (handler! = null) {pipeline.addLast (handler) } ch.eventLoop () .execute (new Runnable () {@ Overridepublic void run () {/ / p.addLast ()) adds a ServerBootstrapAcceptor// to the pipeline processor of serverChannel, which can be seen from the name that it is an accessor that accepts new requests and throws them to an event loop pipeline.addLast (new ServerBootstrapAcceptor (currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)). }});}});} br

The above code mainly performs the following functions:

Set `option` and `attr` to initialize the `pipeline` of the server `channel` to add a custom `handler` to add the `ServerBootstrapAcceptor` (request accessor) `pipeline` method to the entry of the `Netty Reactor` thread, which we will introduce in the next article. To sum up, we find that when the code is executed, `Netty` does not actually start the service, but initializes some basic configurations and properties and adds an accessor to `pipeline` to specifically accept new connections. The code for registering `Channel` with the event poller to complete the registration of `Channel` is as follows: ChannelFuture regFuture = config (). Group (). Register (channel) The object returned by ```here is `NioEventLoopGroup```java @ Overridepublic ChannelFuture register (Channel channel) {/ / called the register method / / NioEventLoop extends SingleThreadEventLoopreturn next () .register (channel) in the NioEventLoop object } br returns a `EventLoop` object in the `next` method, and each `EventLoop` is bound to a `Selector` bound to the `Selector` in the previous code, so every `Channel` operation is empty, but starting from this line of code, there are `Channel` registration public ChannelFuture register (Channel channel) {return register (channel, this) {return register (channel, this);} public ChannelFuture register (final ChannelPromise promise) {Channel` (promise, "promise") Promise.channel () .unsafe () .register (this, promise); return promise;} br you can see here that the `register` operation is delegated to the `UnSecret` object in `Channel`. Students who have a slight impression of the above object should know that this is the `Unregister` object public final void register (EventLoop eventLoop, final ChannelPromise promise) {/ /. AbstractChannel.this.eventLoop = eventLoop;//... Register0 (promise);} br first binds the `EventLoop` event loop to the `NioServerSocketChannel`, and then calls the `EventLoop` code as follows: 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) }} / / this paragraph is actually very clear. First, call `doRegister () `to register protected void doRegister () throws Exception {boolean selected = false; for (;;) {try {selectionKey = javaChannel (). Register (eventLoop (). UnwrappedSelector (), 0, this); return } catch (CancelledKeyException e) {/ /...}} br here we finally see the process of registering `Channel` to `Selector` at the bottom of `JDK`, but the value of `OPS` here is 0, which means we don't care about any events, while we expect the value of `OPS` to be `OPS`, so the code is not finished yet. After the registration of `Channel`, several methods related to `pipeline` are executed. Later, when we analyze `pipeline` in detail, we will talk about binding private static void doBind0 (final ChannelFuture regFuture, final Channel channel, final SocketAddress localAddress, final ChannelPromise promise) {channel.eventLoop () .execute (new Runnable () {@ Overridepublic void run () {if (regFuture.isSuccess ()) {channel.bind (localAddress, promise) .addListener (ChannelFutureListener.CLOSE_ON_FAILURE) to the server port. } else {promise.setFailure (regFuture.cause ());});} / / execute a task through `EventLoop` in the `EventLoop` method, and then go to the `channel.bind () `method public ChannelFuture bind (SocketAddress localAddress, ChannelPromise promise) {return pipeline.bind (localAddress, promise);} public final ChannelFuture bind (SocketAddress localAddress, ChannelPromise promise) {return tail.bind (localAddress, promise) } br about `Pipeline` will be introduced in subsequent blogs. At present, a better way is to enter `Debug` step by step. At the end of the call chain, we come to the `DefaultChannelPipeline.HeadContext` of `DefaultChannelPipeline.HeadContext`. The code is as follows: public void bind (ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {unsafe.bind (localAddress, promise);} / / the `unSecret` here is the aforementioned `AbstractUnqualified, and the exact point should be `NioMessageUnqualified @ Overridepublic final void bind (final SocketAddress localAddress, final ChannelPromise promise) {/ /. Boolean wasActive = isActive (); / / DoBind (localAddress); if (! wasActive & & isActive ()) {invokeLater (new Runnable () {@ Overridepublic void run () {pipeline.fireChannelActive ();}});} safeSetSuccess (promise) } / / complete the binding operation in the `doBind` method, as follows: protected void doBind (SocketAddress localAddress) throws Exception {if (PlatformDependent.javaVersion () > = 7) {javaChannel (). Bind (localAddress, config.getBacklog ());} else {javaChannel (). Socket (). Bind (localAddress, config.getBacklog ());}} br

Finally, the port is bound by calling the `bind` method in `JDK`. According to the normal process, we have previously analyzed that the `false` is returned by the `pipeline.fireChannelActive () `method. After entering `false`, if `channel` is activated, the call to `pipeline.fireChannelActive ()` will be initiated.

Public void channelActive (ChannelHandlerContext ctx) throws Exception {ctx.fireChannelActive (); readIfIsAutoRead ();} / `pipeline.channelActive` will call the `channelActive` method of each node in `pipeline` one by one, so the `channelActive` of `HeadContext` will be called, that is, the `readIfIsAutoRead` method will be called public void channelActive (ChannelHandlerContext ctx) throws Exception {ctx.fireChannelActive (); readIfIsAutoRead ();} private void readIfIsAutoRead () {if (channel.config (). IsAutoRead ()) {channel.read () }} / / eventually this method will call the `doBeginRead` method protected void doBeginRead () of `AbstractNioChannel` {final SelectionKey selectionKey = this.selectionKey;if (! selectionKey.isValid ()) {return;} readPending = true;final int interestOps = selectionKey.interestOps (); if ((interestOps & readInterestOp) = = 0) {selectionKey.interestOps (interestOps | readInterestOp) }} the `readInterestOp` in the last line of br is the `Accept` mentioned above, that is, let the event poller pay attention to the `Accept` event. So far, we have completed the registration process of `Channel` for the `ACCEPT` event. So far, the code we have seen so far is equivalent to the following code in traditional NIO programming: ServerSocketChannelserverSocketChannel = ServerSocketChannel.open (); / build NioServerSocketChannelserverSocketChannel.configureBlocking (false); / / ch.configureBlocking (false) in AbstractNioChannel; serverSocketChannel.bind (new InetSocketAddress ("localhost", 8888)) / / NioServerSocketChannel.doBind () Selector selector = Selector.open (); / / NioEventLoop.openSelector () serverSocketChannel.register (selector, SelectionKey.OP_ACCEPT) / / AbstractNioChannel.doBeginRead () the main function of the br server is to create a `Channel` and register `Channel` on the `Selector` of `NioEventLoop`. This is the end of "how Netty binds the port and starts the service". Thank you for your reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report