用netty4实现http服务器

public class HttpServer {
    private static final Logger logger = LogManager.getLogger("default");

    public static void main(String[] args) throws InterruptedException, IOException {
        try {
            MetricKafkaHttpServer server = new MetricKafkaHttpServer();
            server.run();
        } finally {
            logger.error("Server shutting down.");
        }
    }

    public void run() throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(workerGroup, bossGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast("inboundDecoder", new HttpRequestDecoder())
                                    .addLast("outboundEncoder", new HttpResponseEncoder()) // 1
                                    .addLast("inboundAggregator", new HttpObjectAggregator(50 * 1024 * 1024))
                                    .addLast("inboundHandler", new HttpRequestHandler());
                        }
                    })
                    //TODO options
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true); // 2

            ChannelFuture f = b.bind(ServerProperties.PORT).sync();
            logger.info("Server started in port " + ServerProperties.PORT + ".");

            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}

1. 一个channel,inbound handler由注册顺序从上往下排列,outbound handler由注册顺序从下往上排列。

2.server端接收请求,没接收一个请求生成一个子channel,处理这个request

public class HttpRequestHandler extends SimpleChannelInboundHandler {


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws UnsupportedEncodingException, IOException {
        //do something with msg, for example
	ByteBuf m = msg.content();
	StringBuilder sb = new StringBuilder();
	while (m.isReadable()) {
		sb.append((char) m.readByte());
	}
	String content = sb.toString();
      //do something with content
	DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer("some_body_content".getBytes())); 
	response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); 
	response.headers().add(HttpHeaderNames.CONTENT_TYPE, "text/plain"); 
	ctx.writeAndFlush(response); 
	} 

	@Override 
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 
		logger.error("Exception caught in netty channel.", cause); ctx.close(); 
	}

}




注意点:netty默认使用ByteBuf存储request和response,它使用直接内存,不在GC堆内,所以不会被自动回收,需要手动回收。request和response一般继承ReferenceCounted接口,维持一个refCnt,可以通过msg.release(),msg.retain()修改,也可以用ReferenceCountUtil.release(msg)来释放。SimpleChannelInboundHandler在ChannelRead0方法退出时会自动释放未释放的资源,而ChannelInboundHandlerAdapter不会,需要手动释放,如不释放,会造成内存泄露

你可能感兴趣的:(java,netty)