public static void main(String[] arg)throws Exception{
//NioEventLoopGroup 死循环
//netty的服务器会启动两个服务器,boss来接收连接,worker用来处理连接及响应。
//本质上都是nio的异步处理的事件循环对象
EventLoopGroup bossG = new NioEventLoopGroup();
EventLoopGroup workerG = new NioEventLoopGroup();
try {
//启动服务器,ServerBootstrap辅助启动封装类
//ServerBootstrap里面封装了netty的相关属性和方法,简化netty服务器的创建工作
ServerBootstrap bootstrap = new ServerBootstrap();
//方法链形式(返回对象),装配启动类属性
bootstrap.group(bossG, workerG)
.channel(NioServerSocketChannel.class)//netty里对nio的ServerSocketChannel进行了封装
.childHandler(new TestServerInitializer());//childHandler针对worker,用来处理交给woeker的连接
//服务器真正启动,
//sync(阻塞方法)用来等待和同步连接
//返回ChannelFuture集成Future,调用异步方法后直接返回Future,里面方法可判断异步操作是否结束
ChannelFuture channelFuture = bootstrap.bind(8899).sync();
//netty关闭操作
channelFuture.channel().closeFuture().sync();
}finally{
//netty优雅关闭?
//如果关闭的时候有连接还没处理,在可控的时间里,把连接处理完,并不接受新的连接
bossG.shutdownGracefully();
workerG.shutdownGracefully();
}
}
public class TestServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception{
//获得channel的管道,可添加编解码器,可用netty提供方法或自定义
//请求处理类TestServerHandler
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("httpServerCodec",new HttpServerCodec());
pipeline.addLast("testServerHandler",new TestServerHandler());
}
}
//SimpleChannelInboundHandler,入栈,数据从外边进来。SimpleChannelOutboundHandler,出栈,把数据发到客户端,
public class TestServerHandler extends SimpleChannelInboundHandler<HttpObject> {
//ChannelHandlerContext 消息对象,HttpObject 请求对象,真正传入的数据类型
//连接进来时 handlerAdded-》channelRegistered-》channelActive-》channelRead0-》channelInactive-》channelUnregistered
@Override
public void channelRead0(ChannelHandlerContext ctx,HttpObject msg)throws Exception{
if(msg instanceof HttpRequest){
out.println("remote address:"+ctx.channel().remoteAddress());
URI url = new URI(((HttpRequest) msg).uri());
if(url.getPath().equals("/favicon.ico")){
out.println("from brows " );
out.println(((HttpRequest) msg).method());
}
ByteBuf content = Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8);
FullHttpResponse res = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1
, HttpResponseStatus.OK,content);
res.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
res.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
ctx.writeAndFlush(res);
ctx.channel().close();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx)throws Exception{
out.println("channel active");
super.channelActive(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx)throws Exception{
out.println("channel registered");
super.channelRegistered(ctx);
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception{
out.println("handler added");
super.handlerAdded(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx)throws Exception{
out.println("channel inactive");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
out.println("channel unregistered");
super.channelUnregistered(ctx);
}
}