利用netty實現一個http服務器

主要分爲五個步驟

  • 設置主從線程組
  • 設置服務器啓動類
  • 爲服務器設置channel
  • 設置啓動類的助手類
  • 監聽和關閉

接下來解釋爲什麼會有這五步:

爲什麼設置主從線程組

放張圖,講述線程模型

爲什麼設置服務器啓動類

這個服務器啓動類,在我看來,相當於管理中心,他負責整體調度,和初始化設置,比如,我們之前創建了主從線程組,他要管理主從線程組,要不然,之前,創建的線程組,放在那裏,怎麼用,沒人管啊!所以,服務器啓動類要管理這些線程組。

爲服務器設置channel

channel,可以理解爲負責IO操作的組件。設置channel是爲了說我建立一個什麼樣的channel,來處理這些請求(設置channel的這個地方,理解的不是很深刻,如果有大神瞭解的比較深入,請在評論解釋一下哈)

設置啓動類的助手類

助手類是說,好了請求來了,現在該怎麼處理呢,那這就由助手類來決定了

監聽和關閉

主要設置使用哪個端口,同步,還是異步。

好了,上代碼

package com.example.netty.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @ClassName HelloServer
 * @Description 實現客戶端發送一個請求,服務器會返回hello netty
 * @Author miaoxu
 * @Date 2019/7/28 23:32
 * @Version 1.0
 **/
public class HelloServer {
    public static void main(String[] args) throws InterruptedException {
        //主線程組,接受客戶端的鏈接,不做任何處理,和老闆一樣,不做任何事情
        EventLoopGroup bossGroup = new NioEventLoopGroup();

        //從線程組,老闆線程組把任務給他,讓手下線程組做任務
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // netty服務器的創建,ServerBootstrap是一個啓動類
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup) // 設置主從線程組
                            .channel(NioServerSocketChannel.class)// 設置nio的雙向通道
                            .childHandler(new HelloServerInitializer());// 設置字處理器,用於處理workerGroup

            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();

            //監聽關閉的channel,設置位同步方式
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}

package com.example.netty.netty;

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


/**
 * @ClassName HelloServerInitializer
 * @Description 初始化器,channel註冊後,會執行裏面的相應的初始化方法
 * @Author miaoxu
 * @Date 2019/7/28 23:46
 * @Version 1.0
 **/
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //通過SocketChannel獲取對應的管道
        ChannelPipeline channelPipeline = socketChannel.pipeline();

        //通過管道,添加handler
        // HttpServerCodec是由netty自己添加的助手類,可以理解爲攔截器
        // 當請求到服務端,我們需要做編碼,相應到客戶端做編碼
        channelPipeline.addLast("", new HttpServerCodec());
        channelPipeline.addLast("customHandler", new CustomHandler());
    }
}

package com.example.netty.netty;

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.channel.internal.ChannelUtils;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

/**
 * @ClassName CustomHandler
 * @Description 創建自定義的助手類
 * @Author miaoxu
 * @Date 2019/7/28 23:53
 * @Version 1.0
 **/

//對於請求來講,相當於入站,入境
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject>{
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        // 獲取channel
        Channel channel = channelHandlerContext.channel();
        if (httpObject 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_1,
                    HttpResponseStatus.OK,
                    content);
            //爲響應增加數據類型和長度
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());

            //把相應刷到客戶端
            channelHandlerContext.writeAndFlush(response);
        }





    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章