SpringBoot使用netty

Netty是由JBOSS提供的一個java開源框架。java

Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序。算法

也就是說,Netty 是一個基於NIO的客戶、服務器端編程框架,使用Netty能夠確保你快速和簡單的開發出一個網絡應用,例如實現了某種協議的客戶、服務端應用。spring

Netty至關於簡化和流線化了網絡應用的編程開發過程,例如:基於TCP和UDP的socket服務開發。編程

「快速」和「簡單」並不用產生維護性或性能上的問題。Netty是一個吸取了多種協議(包括FTP、SMTP、HTTP等各類二進制文本協議)的實現經驗,並通過至關精心設計的項目。bootstrap

最終,Netty 成功的找到了一種方式,在保證易於開發的同時還保證了其應用的性能,穩定性和伸縮性服務器

本文講解SpringBoot如何使用Netty服務端和客戶端的簡單案例以及相關參數解釋網絡

1、Netty服務端框架

一、導入依賴異步

< dependency>socket

< groupId>org.springframework.boot< /groupId>

< artifactId>spring-boot-starter< /artifactId>

< /dependency>

< dependency>

< groupId>org.projectlombok< /groupId>

< artifactId>lombok< /artifactId>

< /dependency>

< dependency>

< groupId>io.netty< /groupId>

< artifactId>netty-all< /artifactId>

< version>4.1.36.Final< /version>

< /dependency>

二、編寫Netty服務端處理器

/**

  • @author Gjing

  • netty服務端處理器 **/ @Slf4j public class NettyServerHandler extends ChannelInboundHandlerAdapter {

/**

  • 客戶端鏈接會觸發

*/ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception {

log.info("Channel active......");

}

/** * 客戶端發消息會觸發

*/ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

log.info("服務器收到消息: {}", msg.toString());

ctx.write("你也好哦");

ctx.flush();

}

/**

  • 發生異常觸發

*/ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } 三、編寫Netty服務端初始化器

/**

  • @author Gjing
  • netty服務初始化器 **/ public class ServerChannelInitializer extends ChannelInitializer { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { //添加編解碼 socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8)); socketChannel.pipeline().addLast(new NettyServerHandler()); } } 四、編寫Netty服務啓動

/**

  • @author Gjing
  • 服務啓動監聽器 **/ @Component @Slf4j public class NettyServer {

public void start(InetSocketAddress socketAddress) {

//new 一個主線程組

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

//new 一個工做線程組

EventLoopGroup workGroup = new NioEventLoopGroup(200);

ServerBootstrap bootstrap = new ServerBootstrap()

.group(bossGroup, workGroup)

.channel(NioServerSocketChannel.class)

.childHandler(new ServerChannelInitializer())

.localAddress(socketAddress)

//設置隊列大小

.option(ChannelOption.SO_BACKLOG, 1024)

// 兩小時內沒有數據的通訊時,TCP會自動發送一個活動探測數據報文

.childOption(ChannelOption.SO_KEEPALIVE, true);

//綁定端口,開始接收進來的鏈接

try {

ChannelFuture future = bootstrap.bind(socketAddress).sync();

log.info("服務器啓動開始監聽端口: {}", socketAddress.getPort());

future.channel().closeFuture().sync();

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

//關閉主線程組

bossGroup.shutdownGracefully();

//關閉工做線程組

workGroup.shutdownGracefully();

}

} }

五、啓動類

@SpringBootApplication

public class ServerApplication {

public static void main(String[] args) {

SpringApplication.run(ServerApplication.class, args) ; //啓動服務端

NettyServer nettyServer = new NettyServer();

nettyServer.start(new InetSocketAddress("127.0.0.1", 8090));

}

} 六、啓動結果

2、Netty客戶端 一、添加依賴

< dependency>

< groupId>org.springframework.boot< /groupId>

< artifactId>spring-boot-starter< /artifactId>

< /dependency>

< dependency>

< groupId>org.projectlombok< /groupId>

< artifactId>lombok< /artifactId>

< /dependency>

< dependency>

< groupId>io.netty< /groupId>

< artifactId>netty-all< /artifactId>

< version>4.1.36.Final< /version>

< /dependency>

二、編寫客戶端處理器

/**

  • @author Gjing
  • 客戶端處理器 **/ @Slf4j

public class NettyClientHandler extends ChannelInboundHandlerAdapter {

@Override

public void channelActive(ChannelHandlerContext ctx) throws Exception {

log.info("客戶端Active .....");

}

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

log.info("客戶端收到消息: {}", msg.toString());

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

cause.printStackTrace();

ctx.close();

}

}

三、編寫客戶端初始化器

/**

  • @author Gjing

  • 客戶端初始化器

**/ public class NettyClientInitializer extends ChannelInitializer {

@Override

protected void initChannel(SocketChannel socketChannel) throws Exception {

socketChannel.pipeline().addLast("decoder", new StringDecoder());

socketChannel.pipeline().addLast("encoder", new StringEncoder());

socketChannel.pipeline().addLast(new NettyClientHandler());

}

}

四、編寫客戶端

/**

  • @author Gjing

**/ @Component

@Slf4j

public class NettyClient {

public void start() {

EventLoopGroup group = new NioEventLoopGroup();

Bootstrap bootstrap = new Bootstrap()

.group(group)

//該參數的做用就是禁止使用Nagle算法,使用於小數據即時傳輸

.option(ChannelOption.TCP_NODELAY, true)

.channel(NioSocketChannel.class)

.handler(new NettyClientInitializer());

try {

ChannelFuture future = bootstrap.connect("127.0.0.1", 8090).sync();

log.info("客戶端成功....");

//發送消息

future.channel().writeAndFlush("你好啊");

// 等待鏈接被關閉

future.channel().closeFuture().sync();

} catch (InterruptedException e) {

e.printStackTrace();

}finally {

group.shutdownGracefully();

}

}

}

五、啓動類

@SpringBootApplication

public class ClientApplication {

public static void main(String[] args) {

SpringApplication.run(ClientApplication.class, args);

//啓動netty客戶端

NettyClient nettyClient = new NettyClient();

nettyClient.start();

}

} 六、啓動結果

客戶端

服務端

3、ChannelOption參數詳解 一、ChannelOption.SO_BACKLOG

ChannelOption.SO_BACKLOG對應的是tcp/ip協議listen函數中的backlog參數,函數listen(int socketfd,int backlog)用來初始化服務端可鏈接隊列,服務端處理客戶端鏈接請求是順序處理的,因此同一時間只能處理一個客戶端鏈接,多個客戶端來的時候,服務端將不能處理的客戶端鏈接請求放在隊列中等待處理,backlog參數指定了隊列的大小

二、ChannelOption.SO_REUSEADDR

ChanneOption.SO_REUSEADDR對應於套接字選項中的SO_REUSEADDR,這個參數表示容許重複使用本地地址和端口,好比,某個服務器進程佔用了TCP的80端口進行監聽,此時再次監聽該端口就會返回錯誤,使用該參數就能夠解決問題,該參數容許共用該端口,這個在服務器程序中比較常使用,好比某個進程非正常退出,該程序佔用的端口可能要被佔用一段時間才能容許其餘進程使用,並且程序死掉之後,內核一須要必定的時間纔可以釋放此端口,不設置SO_REUSEADDR就沒法正常使用該端口。

三、ChannelOption.SO_KEEPALIVE

Channeloption.SO_KEEPALIVE參數對應於套接字選項中的SO_KEEPALIVE,該參數用於設置TCP鏈接,當設置該選項之後,鏈接會測試連接的狀態,這個選項用於可能長時間沒有數據交流的鏈接。當設置該選項之後,若是在兩小時內沒有數據的通訊時,TCP會自動發送一個活動探測數據報文

四、ChannelOption.SO_SNDBUF和ChannelOption.SO_RCVBUF

ChannelOption.SO_SNDBUF參數對應於套接字選項中的SO_SNDBUF,ChannelOption.SO_RCVBUF參數對應於套接字選項中的SO_RCVBUF這兩個參數用於操做接收緩衝區和發送緩衝區的大小,接收緩衝區用於保存網絡協議站內收到的數據,直到應用程序讀取成功,發送緩衝區用於保存發送數據,直到發送成功。

五、ChannelOption.SO_LINGER

ChannelOption.SO_LINGER參數對應於套接字選項中的SO_LINGER,Linux內核默認的處理方式是當用戶調用close()方法的時候,函數返回,在可能的狀況下,儘可能發送數據,不必定保證會發生剩餘的數據,形成了數據的不肯定性,使用SO_LINGER能夠阻塞close()的調用時間,直到數據徹底發送

六、ChannelOption.TCP_NODELAY

ChannelOption.TCP_NODELAY參數對應於套接字選項中的TCP_NODELAY,該參數的使用與Nagle算法有關,Nagle算法是將小的數據包組裝爲更大的幀而後進行發送,而不是輸入一次發送一次,所以在數據包不足的時候會等待其餘數據的到了,組裝成大的數據包進行發送,雖然該方式有效提升網絡的有效負載,可是卻形成了延時,而該參數的做用就是禁止使用Nagle算法,使用於小數據即時傳輸,於TCP_NODELAY相對應的是TCP_CORK,該選項是須要等到發送的數據量最大的時候,一次性發送數據,適用於文件傳輸。

七、IP_TOS

IP參數,設置IP頭部的Type-of-Service字段,用於描述IP包的優先級和QoS選項。

八、ALLOW_HALF_CLOSURE

Netty參數,一個鏈接的遠端關閉時本地端是否關閉,默認值爲False。值爲False時,鏈接自動關閉;爲True時,觸發ChannelInboundHandler的userEventTriggered()方法,事件爲ChannelInputShutdownEvent。

4、Netty的future.channel().closeFuture().sync();到底有什麼用?

主線程執行到這裏就 wait 子線程結束,子線程纔是真正監聽和接受請求的,closeFuture()是開啓了一個channel的監聽器,負責監聽channel是否關閉的狀態,若是監聽到channel關閉了,子線程纔會釋放,syncUninterruptibly()讓主線程同步等待子線程結果

相關文章
相關標籤/搜索