1. 程式人生 > >基於netty實現http伺服器

基於netty實現http伺服器

匯入netty4的依賴

<dependency>
	   <groupId>io.netty</groupId>
	   <artifactId>netty-all</artifactId>
	   <version>4.1.28.Final</version>
</dependency>

服務端

/**
 * http伺服器
 */
public class Server {

    //執行緒組
    private static final EventLoopGroup group = new NioEventLoopGroup();

    //服務端啟動類
    private static final ServerBootstrap bootstrap = new ServerBootstrap();

    //監聽埠
    private static final int PORT = 6789;

    private static final ServerHandler serverHandler = new ServerHandler();

    //SSL開關
    private static final boolean SSL = true;

    public static void start() throws InterruptedException, CertificateException, SSLException {
        //配置SSL
        final SslContext sslCtx;
        if (SSL) {
            //netty為我們提供的ssl加密,預設
            SelfSignedCertificate ssc = new SelfSignedCertificate();
            sslCtx = SslContextBuilder.forServer(ssc.certificate(),
                    ssc.privateKey()).build();
        } else {
            sslCtx = null;
        }

        //設定執行緒組
        bootstrap.group(group)
                //設定Nio方式的通道監聽客戶端連線
                .channel(NioServerSocketChannel.class)
                //設定埠
                .localAddress(new InetSocketAddress(PORT))
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                        ChannelPipeline pipeline = nioSocketChannel.pipeline();

                        //驗證SSL
                        if (sslCtx != null) {
                            pipeline.addLast(sslCtx.newHandler(nioSocketChannel.alloc()));
                        }

                        //對http請求進行解碼
                        pipeline.addLast("decode", new HttpRequestDecoder());

                        //對http請求進行編碼
                        pipeline.addLast("encode", new HttpResponseEncoder());

                        //對http進行聚合,設定最大聚合位元組長度為10M
                        pipeline.addLast(new HttpObjectAggregator(10 * 1024 * 1024));

                        //開啟http內容壓縮
                        pipeline.addLast(new HttpContentCompressor());

                        //新增自定義處理器
                        pipeline.addLast(serverHandler);
                    }
                });

        System.out.println("服務端已經啟動......");

        //阻塞方法,直到監聽到指定的埠有連線
        ChannelFuture channel = bootstrap.bind().sync();

        //關閉通道
        channel.channel().closeFuture().sync();
    }


    public static void main(String[] args) throws InterruptedException, CertificateException, SSLException {
        Server.start();
    }

}

服務端處理器

/**
 * 服務端處理器
 */

@ChannelHandler.Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {

    private static String result = "";


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("已經獲取到客戶端連線......");
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        FullHttpRequest request = (FullHttpRequest) msg;
        try {
            String uri = request.uri();
            HttpMethod method = request.method();

            if (!"/test".equalsIgnoreCase(uri)) {
                result = "路徑找不到";
                send(ctx, HttpResponseStatus.BAD_REQUEST, result);
                return;
            }

            //get請求
            if (HttpMethod.GET.equals(method)) {
                result = "get請求: " + System.getProperty("line.separator") + RespConstant.getNews();
                send(ctx, HttpResponseStatus.OK, result);
            } else if (HttpMethod.POST.equals(method)) {
                //.....
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            request.release();
        }

    }

    //響應
    private void send(ChannelHandlerContext ctx, HttpResponseStatus status, String result) {
        //聚合響應,並設定http配置
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(result, CharsetUtil.UTF_8)
        );

        //設定響應headers
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");

        //新增監聽,等所有資料全部響應完了之後再關閉資源
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}

響應工具類

/**
 * 響應訊息
 */
public class RespConstant {
    private static final String[] NEWS = {
            "她那時候還太年輕,不知道所有命運贈送的禮物,早已在暗中標好了" +
                    "價格。——斯蒂芬·茨威格《斷頭皇后》",
            "這是一個最好的時代,也是一個最壞的時代;" +
                    "這是一個智慧的年代,這是一個愚蠢的年代;\n" +
                    "這是一個信任的時期,這是一個懷疑的時期;" +
                    "這是一個光明的季節,這是一個黑暗的季節;\n" +
                    "這是希望之春,這是失望之冬;" +
                    "人們面前應有盡有,人們面前一無所有;\n" +
                    "人們正踏上天堂之路,人們正走向地獄之門。 —— 狄更斯《雙城記》",
    };

    private static final Random R = new Random();

    public static String getNews() {
        return NEWS[R.nextInt(NEWS.length)];
    }

}