Netty ServerBootstrap如何绑定端口
这篇讲netty服务端ServerBootstrap如何启动
前言
BootStrap在netty的应用程序中负责引导服务器和客户端。netty包含了两种不同类型的引导:
- 使用服务器的ServerBootStrap,用于接受客户端的连接以及为已接受的连接创建子通道。
- 用于客户端的BootStrap,不接受新的连接,并且是在父通道类完成一些操作。
一般服务端的代码如下所示:
public final class SimpleServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new SimpleServerHandler())
.childHandler(new SimpleServerInitializer())
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
private static class SimpleServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelRegistered");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerAdded");
}
}
public class SimpleServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:" + ch.remoteAddress()+"连接上");
}
}
在上篇博文(插入上篇文章)中 剖析了如下的两行代码内部的构造函数中干了些什么。
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap如何启动
本篇文章将分析如下几行代码里面做了些什么。
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new SimpleServerHandler())
.childHandler(new SimpleServerInitializer())
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);

我们看下构造函数将workerGroup保存在 ServerBootstrap对象的childGroup属性上。 bossGroup保存在ServerBootstrap对象的group属性上
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
super.group(parentGroup);
if (childGroup == null) {
throw new NullPointerException("childGroup");
}
if (this.childGroup != null) {
throw new IllegalStateException("childGroup set already");
}
this.childGroup = childGroup;
return this;
}
设置父类属性channelFactory 为: BootstrapChannelFactory类的对象。其中这里BootstrapChannelFactory对象中包括一个class属性为:NioServerSocketChannel.class,从如下该类的构造函数中可以明显的得到这一点。
public B channel(Class<? extends C> channelClass) {
if (channelClass == null) {
throw new NullPointerException("channelClass");
}
return channelFactory(new BootstrapChannelFactory<C>(channelClass));
}
public B channelFactory(ChannelFactory<? extends C> channelFactory) {
if (channelFactory == null) {
throw new NullPointerException("channelFactory");
}
if (this.channelFactory != null) {
throw new IllegalStateException("channelFactory set already");
}
this.channelFactory = channelFactory;
return (B) this;
}
并且BootstrapChannelFactory中提供 newChannel()方法,我们可以看到 clazz.newInstance(),主要是通过反射来实例化NioServerSocketChannel.class
rivate static final class BootstrapChannelFactory<T extends Channel> implements ChannelFactory<T> {
private final Class<? extends T> clazz;
BootstrapChannelFactory(Class<? extends T> clazz) {
this.clazz = clazz;
}
@Override
public T newChannel() {
try {
return clazz.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + clazz, t);
}
}
@Override
public String toString() {
return StringUtil.simpleClassName(clazz) + ".class";
}
}
这里的handler函数的入参类是我们自己提供的。如下,后面的博文中将会分析这个handler将会在哪里以及何时被调用,这里只需要记住这一点即可
public B handler(ChannelHandler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
return (B) this;
}
由最后一句可知,其实就是讲传入的childHandler赋值给ServerBootstrap的childHandler属性。
该函数的主要作用是设置channelHandler来处理客户端的请求的channel的IO。 这里我们一般都用ChannelInitializer这个类的实例或则继承自这个类的实例
这里我是通过新建类SimpleChatServerInitializer继承自ChannelInitializer。具体的代码如下
public ServerBootstrap childHandler(ChannelHandler childHandler) {
if (childHandler == null) {
throw new NullPointerException("childHandler");
}
this.childHandler = childHandler;
return this;
}
由最后一句可知,其实就是讲传入的childHandler赋值给ServerBootstrap的childHandler属性。
该函数的主要作用是设置channelHandler来处理客户端的请求的channel的IO。 这里我们一般都用ChannelInitializer这个类的实例或则继承自这个类的实例
这里我是通过新建类SimpleChatServerInitializer继承自ChannelInitializer。具体的代码如下:
public class SimpleChatServerInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChatServerHandler());
System.out.println("SimpleChatClient:" + ch.remoteAddress()+"连接上");
}
}
我们再看看ChannelInitializer这个类的继承图可知ChannelInitializer其实就是继承自ChannelHandler的

可知,这个类其实就是往pipeline中添加了很多的channelHandler。
ServerBootstrap的option
这里调用的是父类的AbstractBootstrap的option()方法,源码如下:
public <T> B option(ChannelOption<T> option, T value) {
if (option == null) {
throw new NullPointerException("option");
}
if (value == null) {
synchronized (options) {
options.remove(option);
}
} else {
synchronized (options) {
options.put(option, value);
}
}
return (B) this;
}
其中最重要的一行代码就是:
options.put(option, value);
这里用到了options这个参数,在AbstractBootstrap的定义如下:
private final Map<ChannelOption, Object> options = new LinkedHashMap, Object>();
可知是私有变量,而且是一个Map集合。这个变量主要是设置TCP连接中的一些可选项,而且这些属性是作用于每一个连接到服务器被创建的channel。
ServerBootstrap的childOption
这里调用的是父类的ServerBootstrap的childOption()方法,源码如下:
public <T> ServerBootstrap childOption(ChannelOption<T> childOption, T value) {
if (childOption == null) {
throw new NullPointerException("childOption");
}
if (value == null) {
synchronized (childOptions) {
childOptions.remove(childOption);
}
} else {
synchronized (childOptions) {
childOptions.put(childOption, value);
}
}
return this;
}
这个函数功能与option()函数几乎一样,唯一的区别是该属性设定只作用于被acceptor(也就是boss EventLoopGroup)接收之后的channel。到此为止netty的初始化设置完成,下篇文章我们讲一下启动过程。
结束
结束
识别下方二维码!回复:
入群,扫码加入我们交流群!

Netty ServerBootstrap如何绑定端口的更多相关文章
- 【Netty源码分析】Netty服务端bind端口过程
这一篇博客我们介绍一下Netty服务端绑定端口的过程,我们通过跟踪代码一直到NIO原生绑定端口的操作. 绑定端口操作 ChannelFuture future = serverBootstrap.bi ...
- Netty源码分析第1章(Netty启动流程)---->第5节: 绑定端口
Netty源码分析第一章:Netty启动步骤 第五节:绑定端口 上一小节我们学习了channel注册在selector的步骤, 仅仅做了注册但并没有监听事件, 事件是如何监听的呢? 我们继续跟第一小节 ...
- Netty源码分析--Channel注册&绑定端口(下)(七)
接下来,我们看到的就是两个非常重要的方法 就是 processSelectedKeys() 和 runAllTasks() 方法了. selectionKey中ready的事件,如accept.co ...
- nginx 域名绑定 域名, nginx 域名绑定 端口
一.nginx 域名绑定 域名 nginx绑定多个域名可又把多个域名规则写一个配置文件里,也可又分别建立多个域名配置文件,我一般为了管理方便,每个域名建一个文件,有些同类域名也可又写在一个总的配置文件 ...
- [CISCO] Telete/SSH 之 Port 绑定/端口安全
[网络] Telete/SSH 之 Port 绑定/端口安全 一.前言 之前写完了网络] DHCP 之 Mac 绑定,CiSCO 交换机配置 SSH 登陆.这次我们再试试能不能挖的在深入些. (1) ...
- tomcat绑定域名绑定端口及更换ROOT目录
一.更换ROOT目录 tomcat默认网站目录为 webapps/ROOT ,那么我们如何改为自己的网站目录呢? 1.打开并编辑tomcat目录下的 conf/server.xml 大约在148行的位 ...
- 如何解决飞秋FeiQ绑定端口错误
今天启动feiQ居然报错,绑定端口2425错误,如您正使用FeiQ或IPMsg,请先退出. error = 10049... 百度谷歌之后,本人如此解决 1.netstat -an 查看端口 2425 ...
- Netty+Tomcat热部署端口占用解决办法(转)
在eclipse使用maven deploy (tomcat:deploy) 热部署netty项目 ,项目启动的时候会报错端口被占用. java.net.BindException: Address ...
- MulticastSocket绑定端口的问题
该文章由 Binkery 发布于 Binkery技术博客 http://www.binkery.com 如转载请注明出处,该文章的链接地址为 http://www.binkery.com/archiv ...
随机推荐
- win10家庭版无法访问samba
1:本教程只针对win10家庭版用户,右键点击电脑选择属性就能看到自己的版本.(因为win10家庭版没有本地策略组) 2:针对一下连接不上的情况 3:连接不上的情况 ① : ...
- (opencv5)轮廓检测函数
(opencv5)轮廓检测函数 contours, hierarchy = cv2.findContours(img, mode, method,[offset) 注意 : 1.输入为二值图像,黑色为 ...
- 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了
最近我们项目升级到了 Spring Boot 2.4.6 + Spring Cloud 2020.0.x,通过我的另一系列即可看出:Spring Cloud 升级之路.但是升级后,我们发现 Young ...
- Feign实战技巧篇
介绍Feign在项目中的正确打开方式 看了上一期Feign远程调用的小伙伴可能会问:阿鉴,你不是说上一期讲的是Feign的99%常用方式吗?怎么今天还有正确打开方式一说呀? 阿鉴:是99%的常用方式, ...
- RHCSA_DAY11
删除逻辑卷 逻辑卷的删除不允许联机操作,需要先卸载,在执行删除 在执行删除操作时,首先删除LV逻辑卷,在删除VG卷组,最后删除PV物理卷 删除命令:lvremove #删除逻辑卷错误示范 [root@ ...
- C++ //构造函数调用规则 //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) //析构函数(空实现) //拷贝函数(值拷贝) //2.如果我们写了有参构造函数 编译器就不会提供默认构造函数 但是会提供拷贝构造函数 //3.如果我们写了拷贝函数 编译器就不再提供 默认 有参 构造函数
//构造函数调用规则 #include <iostream> using namespace std; //1.创建一个类,C++编译器会给每个类添加至少3个函数 //默认构造(空实现) ...
- javaSE基础之变量,常量,作用域和运算符
变量 变量是什么? 变量是可以变化得量 Java是一种强类型语言,每个变量都必须声明其类型. Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域 type varName [=v ...
- 分时函数 & 节流函数
分时函数 & 节流函数 1.函数节流 JavaScript 中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合 理,否则我们一般不会遇到跟性能相关的问题.但在一些少数情况下 ...
- oracle、postgres、mysql数据库的建库、创建用户、导人导出备份总结
本文包含的内容:使用命令操作oracle.postgres.mysql的导入导出,登录到数据,创建用户 注:我在公司使用的是Center OS操作系统,所以oracle和postgres均是在Linu ...
- DrJava试用笔记
安装方便:只要配好JAVA_HOME,用java -jar drjava-stable-20120818-r5686.jar即可启动,算是绿色软件: 特色功能:交互式命令行,可以在调试程序时改变变量值 ...
