netty-bind

ServerBootstrap在bind时,主要做了3个操作:init、register、bind

init

 1 void init(Channel channel) throws Exception {
 2   final Map<ChannelOption<?>, Object> options = options0();
 3   synchronized (options) {
 4     setChannelOptions(channel, options, logger);
 5   }
 6
 7   final Map<AttributeKey<?>, Object> attrs = attrs0();
 8   synchronized (attrs) {
 9     for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
10       @SuppressWarnings("unchecked")
11       AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
12       channel.attr(key).set(e.getValue());
13     }
14   }
15
16   ChannelPipeline p = channel.pipeline();
17
18   final EventLoopGroup currentChildGroup = childGroup;
19   final ChannelHandler currentChildHandler = childHandler;
20   final Entry<ChannelOption<?>, Object>[] currentChildOptions;
21   final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
22   synchronized (childOptions) {
23     currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
24   }
25   synchronized (childAttrs) {
26     currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
27   }
28     //register后,ChannelInitializer的initChannel就会通过ChannelPipeline的fireChannelRegistered被调用,
29     //initChannel方法返回后,ChannelInitializer会被从ChannelPipeline中删除。
30     //pipeline.addLast(handler)会将我们设置的handler添加在pipeline中,如果我们添加的是一个ChannelInitializer,
31     //执行完这个initChannel后,ChannelPipeline中就会有ChannelInitializer、ServerBootstrapAcceptor两个Handler,
32     //registered事件继续在ChannelPipeline中传播,传至新添加的ChannelInitializer时,又会执行initChannel逻辑,
33     //我们通常会在initChannel方法中进行添加handler操作,假设添加了h1、h2,
34     //如果不通过execute执行添加ServerBootstrapAcceptor的操作(execute会将任务入队),
35     //最后ChannelPipeline中就会有ServerBootstrapAcceptor、h1、h2。
36   p.addLast(new ChannelInitializer<Channel>() {
37     @Override
38     public void initChannel(final Channel ch) throws Exception {
39       final ChannelPipeline pipeline = ch.pipeline();
40       ChannelHandler handler = config.handler();
41       if (handler != null) {
42         pipeline.addLast(handler);
43       }
44
45       ch.eventLoop().execute(new Runnable() {
46         @Override
47         public void run() {
48             //ServerBootstrapAcceptor
49           pipeline.addLast(new ServerBootstrapAcceptor(
50                   ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
51         }
52       });
53     }
54   });
55 }

ServerBootstrapAcceptor主要就是将channel注册到selector上

 1 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
 2     //......
 3
 4     public void channelRead(ChannelHandlerContext ctx, Object msg) {
 5         //io.netty.channel.Channel,该channel是对jdk的channel的包装,
 6         //在serverSocket accept到socket后,socket就会被包装为io.netty.channel.Channel,
 7         //然后通过pipeline.fireChannelRead传到这里,目前这一系列操作都是在boss线程中进行的。
 8       final Channel child = (Channel) msg;
 9         //将childHandler添加到accept的channel上
10       child.pipeline().addLast(childHandler);
11
12       setChannelOptions(child, childOptions, logger);
13
14       for (Entry<AttributeKey<?>, Object> e: childAttrs) {
15         child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
16       }
17
18       try {
19           //注册Channel,注册后channel就绑定在了特定的EventLoop上,
20           //并且注册在与EventLoop对应的selector上,该channel之后的IO操作都是在EventLoop上进行的。
21         childGroup.register(child).addListener(new ChannelFutureListener() {
22           @Override
23           public void operationComplete(ChannelFuture future) throws Exception {
24             if (!future.isSuccess()) {
25               forceClose(child, future.cause());
26             }
27           }
28         });
29       } catch (Throwable t) {
30         forceClose(child, t);
31       }
32     }
33
34     //......
35 }

register

register和bind都涉及到一个接口io.netty.channel.Channel.Unsafe

 1 //Unsafe提供了提供了与真正的IO操作,比如从socket读数据、写数据,将channel注册到selector等。
 2 interface Unsafe {
 3     //......
 4
 5     void bind(SocketAddress localAddress, ChannelPromise promise);
 6
 7     void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
 8
 9     void write(Object msg, ChannelPromise promise);
10
11     void flush();
12
13     /**
14      * Schedules a read operation that fills the inbound buffer of the first {@link ChannelInboundHandler} in the
15      * {@link ChannelPipeline}.  If there‘s already a pending read operation, this method does nothing.
16      */
17     void beginRead();
18
19     /**
20      * Register the {@link Channel} of the {@link ChannelPromise} and notify
21      * the {@link ChannelFuture} once the registration was complete.
22      */
23     void register(EventLoop eventLoop, ChannelPromise promise);
24
25     //......
26 }
 1 //Unsafe实现的register方法,有删减
 2 public final void register(EventLoop eventLoop, final ChannelPromise promise) {
 3     //如果在worker线程中,则直接注册(即将channel注册在selector上)
 4     if (eventLoop.inEventLoop()) {
 5         register0(promise);
 6     } else {
 7         //如果不在worker线程中,则异步注册,如果worker线程未开启,execute会先开启线程再入队。
 8         eventLoop.execute(new Runnable() {
 9             @Override
10             public void run() {
11                 register0(promise);
12             }
13         });
14     }
15 }

bind

注册之后,就可以bind了,bind仍然会在eventLoop中执行,此后serverSocket就开始监听client请求了。

时间: 2024-10-25 19:16:43

netty-bind的相关文章

Netty对Protocol Buffer多协议的支持(八)

Netty对Protocol Buffer多协议的支持(八) 一.背景 在上篇博文中笔者已经用代码演示了如何在netty中使用Protocol Buffer,然而细心的用户可能会发现一个明显的不足之处就是,我们的Handler只能处理一种特定的类型,而我们的项目中又不可能只有一种类型,那么这个问题该怎么解决了?多的不说,笔者直接上代码. 二.代码实现 2.1 message的编写 syntax = "proto2"; package com.rsy.netty.protobuf; op

netty 解决TCP粘包与拆包问题(二)

TCP以流的方式进行数据传输,上层应用协议为了对消息的区分,采用了以下几种方法. 1.消息固定长度 2.第一篇讲的回车换行符形式 3.以特殊字符作为消息结束符的形式 4.通过消息头中定义长度字段来标识消息的总长度 一.采用指定分割符解决粘包与拆包问题 服务端 1 package com.ming.netty.nio.stickpack; 2 3 4 5 import java.net.InetSocketAddress; 6 7 import io.netty.bootstrap.ServerB

用Netty解析Redis网络协议

用Netty解析Redis网络协议 根据Redis官方文档的介绍,学习了一下Redis网络通信协议.然后偶然在GitHub上发现了个用Netty实现的Redis服务器,很有趣,于是就动手实现了一下! 1.RESP协议 Redis的客户端与服务端采用一种叫做 RESP(REdis Serialization Protocol)的网络通信协议交换数据.RESP的设计权衡了实现简单.解析快速.人类可读这三个因素.Redis客户端通过RESP序列化整数.字符串.数据等数据类型,发送字符串数组表示参数的命

Netty利用ChannelGroup广播消息

在Netty中提供了ChannelGroup接口,该接口继承Set接口,因此可以通过ChannelGroup可管理服务器端所有的连接的Channel,然后对所有的连接Channel广播消息. Server端: public class BroadCastServer { public static void run(int port) { EventLoopGroup boss = new NioEventLoopGroup(); EventLoopGroup worker = new NioE

nio原理/netty简单应用

一.非阻塞IO模式原理 与阻塞模式对应的另一种模式叫非阻塞IO模式,在整个通信过程中读和写操作不会阻塞,当前处理线程不存在阻塞情况.从A机器到B机器它的通信过程是:A机器一条线程将通道设置为写事件后往下执行,而另外一条线程遍历到此通道有字节要写并往socket写数据,B机器一条线程遍历到此通道有字节要读,交给另外一条线程对socket读数据,处理完又把通道设置为写事件,遍历线程遍历到此通道有字节要写,又往socket写数据传往A机器,不断往下循环此操作直到完成通信.这个过程每台机器都有两类主要线

Netty实践(一):轻松入门

前言 Netty作为目前世界上最流行的NIO框架之一,在功能.性能.健壮性方面首屈一指,而且在很多项目中得到验证,比如消息中间件RocketMQ.分布式通信框架Dubbox.Netty内部实现复杂,但是提供给外界的API却十分简单,轻松的让我们的网络处理代码和业务逻辑处理代码分离开,从而快速的开发网络应用. 如果你还不了解JAVA NIO,JAVA SOCKET,可以先参考博主以前关于这方面的博客:<走进Java NIO的世界>.<Java NIO 服务器与客户端实现文件下载>.&

Netty解决TCP粘包/拆包问题 - 按行分隔字符串解码器

服务端 package org.zln.netty.five.timer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; impo

Netty学习之服务器端创建

一.服务器端开发时序图 图片来源:Netty权威指南(第2版) 二.Netty服务器端开发步骤 使用Netty进行服务器端开发主要有以下几个步骤: 1.创建ServerBootstrap实例 ServerBootstrap b=new ServerBootstrap(); ServerBootstrap是Netty服务器端的启动辅助类,提供了一系列的方法用于设置服务器端启动相关的参数. 2.设置并绑定Reactor线程池 EventLoopGroup bossGruop=new NioEvent

Netty

Netty:数据处理流程 Netty作为异步的.事件驱动一个网络通信框架,使用它可以帮助我们快速开发高性能高可靠性的网络服务. 为了更好的使用Netty来解决开发中的问题,学习Netty是很有必要的. Netty现在主流有三个版本:Netty3.Netty4.Netty5.这三个版本中,变化最大的要数线程模型了,各版本的线程模型均不相同.但是有一点是变化不大的,那就是Channel模型,因而数据处理流程也不会有太大的变化.所以本篇就来说一下Netty的数据处理流程,各版本的线程模型会后续说明.

Netty 5用户指南

Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络服务器和客户端程序.换句话说,Netty是一个NIO框架,使用它可以简单快速地开发网络应用程序,比如客户端和服务端的协议.Netty大大简化了网络程序的开发过程比如TCP和UDP的 Socket的开发. "快速和简单"并不意味着应用程序会有难维护和性能低的问题,Netty是一个精心设计的框架,它从许多协议的实现中吸收了很多的经验比如FTP.SMTP.HTTP.许多二进制和基于文本的传统协议,Netty在不