说明
- 服务端通过io.netty.bootstrap.ServerBootstrap启动,ServerBootstrap的 childHandler(ChannelHandler childHandler)函数用于增加处理客户端的ChannelHandler。
- 这个childHandler一般是ChannelInitializer的子类,用于配置ChannelPipeline,在ChannelPipeline中增加处理这个客户端的ChannelHandler。一个ChannelPipeline中通常添加多个ChannelHandler。
- 每当一个新的客户端接入进来,服务端都会针对该客户端创建一新的Channel,对应地,创建新的ChannelPipeline、在ChannelPipeline中增加ChannelHandler。
- 当完成ChannelPipeline的启动配置后,ChannelInitializer会自己删除自己。
- 当客户端断开和服务端的连接后,服务端会删除给该客户端服务的Channel、ChannelPipeline、ChannelHandler。
示例
服务端代码片段
package com.thb.power.server;
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;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
* 服务端的主函数
* @author thb
*
*/
public class MainStation {
static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));
public static void main(String[] args) throws Exception {
// 配置服务器
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new MainStationInitializer());
// 启动服务端
ChannelFuture f = b.bind(PORT).sync();
// 等待直到server socket关闭
f.channel().closeFuture().sync();
} finally {
// 关闭所有event loops以便终止所有的线程
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
package com.thb.power.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
public class MainStationInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new ServerHandler());
System.out.println("MainStationInitializer.initChannel is invoked");
}
}
package com.thb.power.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class ServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
System.out.println(ctx.handler() + " added");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) {
System.out.println(ctx.handler() + " removed");
}
}
启动服务端
从上面输出可以看出,服务端已经正常启动。
启动第一个客户端、观察服务端的输出
从上面服务端新增的输出可以看出,第一个客户端连接上来,ServerHandler的一个实例被增加进来(其实是增加到处理第一个客户端的Channel对应的ChannelPipeline中),MainStationInitializer的initChannel函数被执行。MainStationInitializer是ChannelInitializer的子类。
启动第二个客户端、观察服务端的输出
第二个客户端连接上来,服务端新增如下输出:
从上面服务端新增的输出可以看出,第二个客户端连接上来,ServerHandler的另外一个实例被增加进来(其实是增加到处理第二个客户端的Channel对应的ChannelPipeline中),MainStationInitializer的initChannel函数被执行。不要忘了,MainStationInitializer也是一个ChannelHandler。
退出第一个客户端,观察服务端的输出
在第一个客户端的窗口按Ctrl c,退出第一个客户端。
服务端新增如下输出:
从上面新增的输出可以看出,ServerHandler的第1个实例被移除。
退出第二个客户端,观察服务端的输出
在第二个客户端的窗口按Ctrl c,退出第二个客户端。
服务端新增如下输出:
从上面新增的输出可以看出,ServerHandler的第2个实例被移除。