1. 程式人生 > >netty學習一:用netty構造http服務的小demo

netty學習一:用netty構造http服務的小demo

概述

netty可以支援http、socket、websocket,本文會做一個小demo,簡單介紹一下如何用netty搭建一個http服務。

netty雖然可以提供http服務,但是相比spring mvc、struts2等框架,netty顯得比較底層,很多spring mvc提供的功能,netty統統都沒有。

步驟

編寫netty程式的步驟都比較相似:
1、 啟動group監聽客戶端請求
2、編寫Initializer新增handler
3、自定義業務handler

啟動group監聽客戶端請求

package http;

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; public class HttpServer { public static void main(String[] args) throws InterruptedException { // 接收連線,但是不處理 EventLoopGroup parentGroup = new
NioEventLoopGroup(); // 真正處理連線的group EventLoopGroup childGroup = new NioEventLoopGroup(); try { //載入Initializer ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(parentGroup, childGroup) .channel(NioServerSocketChannel.class) //這裡的childHandler是服務於childGroup的,如果直接使用
//handler方法新增處理器,則是服務於parentGroup的 .childHandler(new HttpServerInitializer()); //繫結監聽埠 ChannelFuture channelFuture = serverBootstrap.bind(8899).sync(); channelFuture.channel().closeFuture().sync(); } finally { parentGroup.shutdownGracefully(); childGroup.shutdownGracefully(); } } }

EventLoopGroup類似死迴圈,一直監聽8899埠是否有請求到達。

編寫Initializer新增handler

package http;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;

public class HttpServerInitializer extends ChannelInitializer<SocketChannel>{
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        //處理http服務的關鍵handler
        pipeline.addLast("httpServerCodec",new HttpServerCodec());
        //自定義的handler
        pipeline.addLast("testHttpServerHandler",new HttpServerHandler());
    }
}

自定義業務handler

package http;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.CharsetUtil;

public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject>{
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        if (msg instanceof HttpRequest) {
            HttpRequest httpRequest = (HttpRequest)msg;
            System.out.println("請求方法名稱:"+httpRequest.method().name());
            System.out.println("請求來自:"+ctx.channel().remoteAddress());

            ByteBuf content = Unpooled.copiedBuffer("Hello World!",CharsetUtil.UTF_8);
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 
                    HttpResponseStatus.OK,
                    content);

            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());

            ctx.writeAndFlush(response);
            ctx.channel().close();
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println("handler add");
        super.handlerAdded(ctx);
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel registed");
        super.channelRegistered(ctx);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel active");
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel inactive");
        super.channelInactive(ctx);
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channel unregisted");
        super.channelUnregistered(ctx);
    }
}

測試

執行main方法啟動netty http程式,並使用curl命令測試。

輸出結果如下:

handler add
channel registed
channel active
請求方法名稱:GET
請求來自:/0:0:0:0:0:0:0:1:52291
channel inactive
channel unregisted

csdn code 路徑

這個專案的原始碼放置在csdn code上,歡迎訪問。