Netty網(wǎng)絡(luò)編程實(shí)戰(zhàn)之搭建Netty服務(wù)器
一、Netty是什么
Netty是JBOSS開源的一款NIO網(wǎng)絡(luò)編程框架,可用于快速開發(fā)網(wǎng)絡(luò)的應(yīng)用。Netty是一個異步的、基于事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用框架,用于快速開發(fā)高性能的服務(wù)端和客戶端??梢詷O大的簡化基于TCP、UDP等協(xié)議的網(wǎng)絡(luò)服務(wù)。并且Netty對于各種傳輸類型(阻塞或非阻塞式的socket)、通信方式(HTTP或websocket)都提供了統(tǒng)一的API接口,提供了靈活的可擴(kuò)展性,高度可自定義的線程模型(多線程、線程池等),支持使用無連接的數(shù)據(jù)報UDP進(jìn)行通信,具有高吞吐量、低延遲、資源消耗低、最低限度的內(nèi)存復(fù)制等特性。除了優(yōu)越的性能外,Netty還支持SSL/TLS和StartTLS等加密傳輸協(xié)議,保證了數(shù)據(jù)傳輸?shù)陌踩浴?/p>
在實(shí)際使用時,Netty可以作為Socket編程的中間件;也可以和Protobuf技術(shù)結(jié)合使用,實(shí)現(xiàn)一個RPC框架,實(shí)現(xiàn)遠(yuǎn)程過程調(diào)用;也可以作為一個websocket的長鏈接服務(wù)器,實(shí)現(xiàn)客戶端和服務(wù)端的長連接通信。
二、Hello Netty
使用Netty作為一個Web服務(wù)器,用于接收用戶請求并給出響應(yīng)。
Netty程序一般都是按套路來寫,依次編寫主程序類、自定義初始化器、自定義處理器。
1、主程序類MyNettyServerTest
通過ServerBootstrap注冊serverGroup和clientGroup兩個事件循環(huán)組,其中serverGroup用于獲取客戶端連接,clientGroup用于處理客戶端連接,類似于常見的Master-Slave結(jié)構(gòu)。
2、初始化器MyNettyServerInitializer
繼承Netty提供的初始化器ChannelInitializer。
Netty封裝了各種各樣的內(nèi)置處理器,用于實(shí)現(xiàn)各種功能。并且ChannelInitializer的initChannel()方法會在某一個連接注冊到Channel后立即被觸發(fā)調(diào)用。因此,可以根據(jù)業(yè)務(wù)需求,在initChannel()中添加若干個Netty內(nèi)置處理器,利用Netty強(qiáng)大的類庫直接處理大部分業(yè)務(wù)。最后再在initChannel()中添加一個自定義處理器,用于實(shí)現(xiàn)特定業(yè)務(wù)的具體功能。
3、自定義處理器MyNettyServerHandler
繼承SimpleChannelInboundHandler,該父類的channelRead0()方法可以接收客戶端的所有請求,并作出響應(yīng),輸出“Hello Netty”。
簡單講,Netty程序就是通過主程序類關(guān)聯(lián)自定義初始化器,然后在初始化器中加入Netty內(nèi)置處理器和自定義處理器,最后在自定義處理器中編寫處理特定需求的業(yè)務(wù)代碼。
三、代碼實(shí)例
1、maven中加入netty-all
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.68.Final</version>
</dependency>
2、主程序類MyNettyServerTest
package com.guor.demo.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;
/**
* 主程序類
*/
public class MyNettyServerTest {
public static void main(String[] args) throws InterruptedException {
/**
* EventLoopGroup:事件循環(huán)組,是一個線程池,也是一個死循環(huán),用于不斷地接收用戶請求;
* serverGroup:用戶監(jiān)聽及建立連接,并把每一個連接抽象為一個channel,最后再將連接交給clientGroup處理;
* clientGroup:真正的處理連接
*/
EventLoopGroup serverGroup = new NioEventLoopGroup();
EventLoopGroup clientGroup = new NioEventLoopGroup();
try {
// 服務(wù)端啟動時的初始化操作
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 1、將serverGroup和clientGroup注冊到服務(wù)端的Channel上;
// 2、注冊一個服務(wù)端的初始化器MyNettyServerInitializer;
// 3、該初始化器中的initChannel()方法會在連接被注冊到Channel后立刻執(zhí)行;
// 5、最后將端口號綁定到8080;
ChannelFuture channelFuture = serverBootstrap.group(serverGroup, clientGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new MyNettyServerInitializer()).bind(8080).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
System.out.println(e);
}finally {
serverGroup.shutdownGracefully();
clientGroup.shutdownGracefully();
}
}
}
3、初始化器MyNettyServerInitializer
package com.guor.demo.netty;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* 初始化器
*/
public class MyNettyServerInitializer extends ChannelInitializer<SocketChannel> {
// 連接被注冊到Channel后,立刻執(zhí)行此方法
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 加入netty提供的處理器
pipeline.addLast("HttpServerCodec",new HttpServerCodec());
// 增加自定義處理器MyNettyServerHandler,用于實(shí)際處理請求,并給出響應(yīng)
pipeline.addLast("MyNettyServerHandler",new MyNettyServerHandler());
}
}4、自定義處理器MyNettyServerHandler
package com.guor.demo.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* 自定義處理器
* Inbound代表"進(jìn)入"的請求
*/
public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
// 定義響應(yīng)的內(nèi)容
ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
byteBuf.readableBytes();
// 等響應(yīng)返回給客戶端
channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
}
}
5、通過curl http://localhost:8080訪問Netty服務(wù)

此時,可能會提示curl不是內(nèi)部或外部命令,如何解決?
四、curl不是內(nèi)部或外部命令
1、下載curl for 64-bit
2、將zip解壓到文件夾
3、在環(huán)境變量中配置

五、重寫SimpleChannelInboundHandler中一些重要的回調(diào)方法
1、重寫回調(diào)方法
package com.guor.demo.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* 自定義處理器
* Inbound代表"進(jìn)入"的請求
*/
public class MyNettyServerHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
// 定義響應(yīng)的內(nèi)容
ByteBuf byteBuf = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
DefaultFullHttpResponse defaultFullHttpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, byteBuf);
defaultFullHttpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
byteBuf.readableBytes();
// 等響應(yīng)返回給客戶端
channelHandlerContext.writeAndFlush(defaultFullHttpResponse);
}
/**
* 增加新處理器時,觸發(fā)此方法
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception{
System.out.println("1、handlerAdded、增加了新的處理器");
super.handlerAdded(ctx);
}
/**
* 當(dāng)通道被注冊到一個事件循環(huán)組EventLoop上時,觸發(fā)此方法
*/
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
System.out.println("2、channelRegistered、通道被注冊");
super.channelRegistered(ctx);
}
/**
* 當(dāng)遠(yuǎn)端處于活躍狀態(tài)時(連接到了某個遠(yuǎn)端,可以收發(fā)數(shù)據(jù)),執(zhí)行此方法
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
System.out.println("3、channelActive、通道連接到了遠(yuǎn)端,處于活躍狀態(tài)");
super.channelActive(ctx);
}
/**
* 當(dāng)通道處于非活躍狀態(tài)時(與遠(yuǎn)端斷開了連接),執(zhí)行此方法
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception{
System.out.println("4、channelInactive、通道遠(yuǎn)端斷開了連接,處于非活躍狀態(tài)");
super.channelInactive(ctx);
}
/**
* 當(dāng)通道被取消了注冊時,執(zhí)行此方法
*/
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception{
System.out.println("5、channelUnregistered、通道被取消了注冊");
super.channelUnregistered(ctx);
}
/**
* 當(dāng)程序發(fā)生異常,執(zhí)行此方法
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable e) throws Exception{
System.out.println("6、exceptionCaught、程序發(fā)生了異常");
e.printStackTrace();
ctx.close();
}
}
2、通過curl http://localhost:8080訪問Netty服務(wù)

3、控制臺輸出

4、ctrl + c停止訪問

以上就是Netty網(wǎng)絡(luò)編程實(shí)戰(zhàn)之搭建Netty服務(wù)器的詳細(xì)內(nèi)容,更多關(guān)于搭建Netty服務(wù)器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決創(chuàng)建springboot后啟動報錯:Failed?to?bind?properties?under‘spri
在Spring?Boot項(xiàng)目中,application.properties和application.yml是用于配置參數(shù)的兩種文件格式,properties格式簡潔但不支持層次結(jié)構(gòu),而yml格式支持層次性,可讀性更好,在yml文件中,要注意細(xì)節(jié),比如冒號后面需要空格2024-10-10
用Java設(shè)計模式中的觀察者模式開發(fā)微信公眾號的例子
這篇文章主要介紹了用Java設(shè)計模式中的觀察者模式開發(fā)微信公眾號的例子,這里Java的微信SDK等部分便不再詳述,只注重關(guān)鍵部分和開發(fā)過程中觀察者模式優(yōu)點(diǎn)的體現(xiàn),需要的朋友可以參考下2016-02-02
java基于jdbc實(shí)現(xiàn)簡單學(xué)生管理系統(tǒng)
本文主要主要介紹了java連接mysql數(shù)據(jù)庫的一個簡單學(xué)生系統(tǒng),通過jdbc連接數(shù)據(jù)庫。文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10
Idea如何使用Fast Request接口調(diào)試
這篇文章主要介紹了Idea如何使用Fast Request接口調(diào)試問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Java8 LocalDateTime極簡時間日期操作小結(jié)
這篇文章主要介紹了Java8-LocalDateTime極簡時間日期操作整理,通過實(shí)例代碼給大家介紹了java8 LocalDateTime 格式化問題,需要的朋友可以參考下2020-04-04
Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別)
這篇文章主要介紹了Java基本數(shù)據(jù)類型與封裝類型詳解(int和Integer區(qū)別) ,需要的朋友可以參考下2017-02-02
Java 中的 BufferedWriter 介紹_動力節(jié)點(diǎn)Java學(xué)院整理
BufferedWriter 是緩沖字符輸出流。它繼承于Writer。接下來通過本文給大家分享Java 中的 BufferedWriter知識,需要的朋友參考下吧2017-05-05
java實(shí)現(xiàn)新浪微博Oauth接口發(fā)送圖片和文字的方法
這篇文章主要介紹了java實(shí)現(xiàn)新浪微博Oauth接口發(fā)送圖片和文字的方法,涉及java調(diào)用新浪微博Oauth接口的使用技巧,具有一定參考接借鑒價值,需要的朋友可以參考下2015-07-07

