一、Netty服务器搭建步骤
- 1) 构建一对主从线程池
- 2) 为服务器设置channel
- 3) 设置处理从线程池得助手类初始化起
- 4) 监听启动和关闭服务器
设置Channel初始化器
每一个Channel都是由多个handler共同组成的管道(pipeline),每个管道都类似于一个小助手,需要程序员初始化时自动设置,一个管道可以理解为一个大的拦截器,而里面的handler可以理解为一个小的拦截器。
1. 定义服务启动类
package org.wdzl;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/*
实现客户端发送请求,服务器给与响应 hello netty
*/
//每次客户端和服务器端连接后都会产生一个Channel对象
public class HelloNettyServer {
public static void main(String[] args) throws Exception {
//创建一组线程池组
//主线程池: 用于接收客户端的请求链接,不做任务处理
EventLoopGroup group1 = new NioEventLoopGroup();
//从线程池: 主线程组会把任务交给它,让其做任务
EventLoopGroup group2 = new NioEventLoopGroup();
try{
//创建服务器启动类
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(group1, group2) //设置主从线程池
.channel(NioServerSocketChannel.class) //设置nio双向通道
.childHandler(new HelloNettyServerInitializer()); //添加子处理器,用于处理从线程池交过来的任务
//启动服务,并且设置端口号,同时启动的方式为同步
ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
//监听关闭的channel,设置为同步方式
channelFuture.channel().closeFuture().sync();
}finally {
group1.shutdownGracefully(); //优雅得进行关闭
group2.shutdownGracefully();
}
}
}
2. 定义服务器启动初始化类
package org.wdzl;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/*
初始化器,channel注册之后会执行里面的相应的初始化方法
*/
public class HelloNettyServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
//通过SocketChannel去获取对应的管道
ChannelPipeline pipeline = channel.pipeline();
//通过管道添加handler
//new HttpServerCodec()是由netty自己提供的助手类,可以理解为拦截器
//当请求到服务器,我们需要解码,响应到客户端需要做编码
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
//添加自定义助手类,给客户端浏览器渲染hello netty~
pipeline.addLast("CunstomHandler", new CustomHandler());
}
}
3. 自定义Handler
package org.wdzl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* 自定义助手类
*/
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
//获取channel
Channel channel = ctx.channel();
//需要先判断是否是HttpRequest 不然服务器端就会报错
if(msg instanceof HttpRequest){
//在控制台打印远程地址
System.out.println(channel.remoteAddress());
//定义向客户端发送的数据内容
ByteBuf content = Unpooled.copiedBuffer("Hello netty~", CharsetUtil.UTF_8);
//构建http response(设置版本号以及状态码)
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_0, HttpResponseStatus.OK, content);
//为响应增加数据类型和长度
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
//把响应渲染到html客户端页面上
ctx.writeAndFlush(response);
}
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
System.out.println("channel 注册");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
System.out.println("channel 移除");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
System.out.println("channel 活跃");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception{
System.out.println("channel不活跃");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception{
System.out.println("助手类添加");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception{
System.out.println("助手类移除");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception{
System.out.println("channel 读取完毕");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception{
System.out.println("用户事件触发");
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception{
System.out.println("channel 可写更改");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception{
System.out.println("捕获到异常");
}
}
二、Channel的生命周期

|