- 💖大家好,我是 爪哇小白2021,
- 半路出家的程式員,在從事開發之前在 某省測繪院 玩了一年的飛機,機緣巧合之下發現了更有趣的事情,從此步入了編程的世界… ps:同時也是一個熱愛旅行的航拍小能手!
- 💬 目的:記錄自己的學習歷程,希望你看完之后,能對你有所幫助,不足請指正!共同學習交流 🖊
Netty
Netty 對 JDK 自帶的 NIO 的 API 進行了良好的封裝,解決了上述問題,且 Netty 擁有高性能、吞吐量更高,延遲更低,減少資源消耗,最小化不必要的記憶體復制等優點,
Netty 現在用的是 4.x,5.x 版本已經廢棄,Netty4.x 需要 JDK6 以上版本支持,
場景
互聯網行業:在分布式系統中,各個節點之間需要遠程服務呼叫,高性能的 RPC 框架必不可少,Netty 作為異步高性能的通信框架,往往作為基礎通信組件被這些 RPC 框架使用,典型應用有:阿里分布式服務框架 Dubbo 的 RPC 框架使用 Dubbo 協議進行節點間通信,Dubbo 協議默認使用 Netty 作為基礎通信組件,用于實作,各行程節點之間的內部通信,RocketMQ 底層也是用的 Netty 作為基礎通信組件,
游戲行業:無論是手游服務端還是大型的網路游戲,Java 語言得到了越來越廣泛的應用,Netty 作為高性能的基礎通信組件,它本身提供了 TCP/UDP 和 HTTP 協議堆疊,
大資料領域:經典的 Hadoop 的高性能通信和序列化組件 Avro 的 RPC 框架,默認采用 Netty 進行跨界點通信,它的 Netty Service 基于 Netty 框架二次封裝實作,
說到這就是說netty還是值得去深入學習一番的~

通訊示例-代碼展示
Maven 依賴:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.35.Final</version>
</dependency>
服務端代碼:
public class NettyServer {
public static void main(String[] args) throws Exception {
//創建兩個執行緒組bossGroup和workerGroup, 含有的子執行緒NioEventLoop的個數默認為cpu核數的兩倍
// bossGroup只是處理連接請求 ,真正的和客戶端業務處理,會交給workerGroup完成
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//創建服務器端的啟動物件
ServerBootstrap bootstrap = new ServerBootstrap();
//使用鏈式編程來配置引數
bootstrap.group(bossGroup, workerGroup) //設定兩個執行緒組
.channel(NioServerSocketChannel.class) //使用NioServerSocketChannel作為服務器的通道實作
// 初始化服務器連接佇列大小,服務端處理客戶端連接請求是順序處理的,所以同一時間只能處理一個客戶端連接,
// 多個客戶端同時來的時候,服務端將不能處理的客戶端連接請求放在佇列中等待處理
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {//創建通道初始化物件,設定初始化引數
@Override
protected void initChannel(SocketChannel ch) throws Exception {
//對workerGroup的SocketChannel設定處理器
ch.pipeline().addLast(new NettyServerHandler());
}
});
System.out.println("netty server start,,");
//系結一個埠并且同步, 生成了一個ChannelFuture異步物件,通過isDone()等方法可以判斷異步事件的執行情況
//啟動服務器(并系結埠),bind是異步操作,sync方法是等待異步操作執行完畢
ChannelFuture cf = bootstrap.bind(9000).sync();
//給cf注冊監聽器,監聽我們關心的事件
/*cf.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (cf.isSuccess()) {
System.out.println("監聽埠9000成功");
} else {
System.out.println("監聽埠9000失敗");
}
}
});*/
//對通道關閉進行監聽,closeFuture是異步操作,監聽通道關閉
// 通過sync方法同步等待通道關閉處理完畢,這里會阻塞等待通道關閉完成
cf.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
/**
* 自定義Handler需要繼承netty規定好的某個HandlerAdapter(規范)
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* 讀取客戶端發送的資料
*
* @param ctx 背景關系物件, 含有通道channel,管道pipeline
* @param msg 就是客戶端發送的資料
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("服務器讀取執行緒 " + Thread.currentThread().getName());
//Channel channel = ctx.channel();
//ChannelPipeline pipeline = ctx.pipeline(); //本質是一個雙向鏈接, 出站入站
//將 msg 轉成一個 ByteBuf,類似NIO 的 ByteBuffer
ByteBuf buf = (ByteBuf) msg;
System.out.println("客戶端發送訊息是:" + buf.toString(CharsetUtil.UTF_8));
}
/**
* 資料讀取完畢處理方法
*
* @param ctx
* @throws Exception
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ByteBuf buf = Unpooled.copiedBuffer("HelloClient", CharsetUtil.UTF_8);
ctx.writeAndFlush(buf);
}
/**
* 處理例外, 一般是需要關閉通道
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
客戶端代碼:
public class NettyClient {
public static void main(String[] args) throws Exception {
//客戶端需要一個事件回圈組
EventLoopGroup group = new NioEventLoopGroup();
try {
//創建客戶端啟動物件
//注意客戶端使用的不是 ServerBootstrap 而是 Bootstrap
Bootstrap bootstrap = new Bootstrap();
//設定相關引數
bootstrap.group(group) //設定執行緒組
.channel(NioSocketChannel.class) // 使用 NioSocketChannel 作為客戶端的通道實作
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
//加入處理器
channel.pipeline().addLast(new NettyClientHandler());
}
});
System.out.println("netty client start");
//啟動客戶端去連接服務器端
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9000).sync();
//對關閉通道進行監聽
channelFuture.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
/**
* 當客戶端連接服務器完成就會觸發該方法
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ByteBuf buf = Unpooled.copiedBuffer("HelloServer", CharsetUtil.UTF_8);
ctx.writeAndFlush(buf);
}
//當通道有讀取事件時會觸發,即服務端發送資料給客戶端
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("收到服務端的訊息:" + buf.toString(CharsetUtil.UTF_8));
System.out.println("服務端的地址: " + ctx.channel().remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
總結
Netty 框架的目的就是讓你的業務邏輯從網路基礎應用編碼中分離出來,讓你可以專注業務的開發,而不需要寫一大堆類似 NIO 的網路處理操作,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/423867.html
標籤:其他
上一篇:簡歷專案描述程序詳解
