1. 導包
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.50.Final</version>
</dependency>
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
2. 測試類
package com.springCloud.netty;
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;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 實現客戶端發送請求, 服務器給予響應
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NettyApplication.class)
public class NettyTest {
@Test
public void test() {
// 創建一組線程組
// 主線程: 用於接受客戶端的請求鏈接, 不做任何處理
EventLoopGroup group_main = new NioEventLoopGroup();
// 從線程: 主線程池會把任務交給它, 讓其做任務
EventLoopGroup group_from = new NioEventLoopGroup();
// 創建服務器啓動類
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(group_main, group_from) // 設置主從線程
.channel(NioServerSocketChannel.class) // 設置 NIO 的雙向頻道
.childHandler(new NettyServerInitializer()); // 添加子處理器, 用於處理從線程池的任務
try {
// 啓動服務並設置端口號, 同時啓動方式爲同步
ChannelFuture sync = serverBootstrap.bind(8009).sync();
// 監聽關閉 Channel, 設置爲同步方式.
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2. 初始化器
package com.springCloud.netty;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* 初始化器, channel 註冊之後, 會執行裏面的相應的初始化方法
*/
public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 通過 SocketChannel 去獲取對應的管道
ChannelPipeline pipeline = socketChannel.pipeline();
// 通過管道添加 handler, HttpServerCode: 是由 netty 自己提供的助手類, 可以理解爲攔截器, 當請求到服務器, 我們需要解碼, 響應到客戶端做解碼
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
// 添加自定義助手類, 給客戶端瀏覽器渲染內容
pipeline.addLast("CustomHandler", new CustomHandler());
}
}
3. 自定義助手類
package com.springCloud.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.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* 自定義助手類
*/
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {
/**
*
* @param channelHandlerContext channelHandlerContext
* @param httpObject httpObject
* @throws Exception Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
// 獲取 channel
Channel channel = channelHandlerContext.channel();
// 在控制檯打印遠程地址
System.out.println(channel.remoteAddress());
// 定義向客戶端發送的數據內容
ByteBuf content = Unpooled.copiedBuffer("Hello netty", CharsetUtil.UTF_8);
// 定義 Http response
DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
// 爲響應增加數據類型和長度
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
// 把響應渲染到 Html 客戶端頁面上
channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
super.channelRegistered(ctx);
System.out.println("Channel 註冊");
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
super.channelUnregistered(ctx);
System.out.println("Channel 移除");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
System.out.println("Channel 活躍");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
System.out.println("Channel 不活躍");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
System.out.println("Channel 讀取完畢");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
super.userEventTriggered(ctx, evt);
System.out.println("用戶事件觸發");
}
@Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
super.channelWritabilityChanged(ctx);
System.out.println("Channel 可寫更改");
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
super.handlerAdded(ctx);
System.out.println("助手類的添加");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
System.out.println("捕獲到異常");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
super.handlerRemoved(ctx);
System.out.println("助手類的移除");
}
}
4. 瀏覽效果
瀏覽器
控制檯