主要分爲五個步驟
- 設置主從線程組
- 設置服務器啓動類
- 爲服務器設置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);
}
}
}