Netty簡單demo
上篇博客簡單介紹了Netty的一些基礎概念和組件,這次就來寫一個簡單的demo,因爲公司需要的是TCP服務端,所以這次的demo就寫一個TCP服務端。下面就直接上代碼。
首先是主類,裏面也放着Netty的啓動方法和執行流程。代碼如下:
package nettytrain;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* TCPServerTrain.java
* Description: netty服務端的練習
*
* @author Peng Shiquan
* @date 2020/6/18
*/
public class TCPServerTrain {
//默認端口
private Integer port = 10000;
public TCPServerTrain(Integer port) {
this.port = port;
}
public void run() throws Exception {
// 接收傳入的連接
EventLoopGroup bossGroup = new NioEventLoopGroup();
//處理傳入的連接,一般是bossGroup的二倍
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
//服務端應用開發的入口
ServerBootstrap serverBootstrap = new ServerBootstrap();
//設置主從線程池
serverBootstrap.group(bossGroup, workGroup)
//指定通道channel的類型,因爲是服務端,所以是NioServerSocketChannel
.channel(NioServerSocketChannel.class)
//設置子通道也就是SocketChannel的處理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TCPServerHandler());
}
})
//配置ServerSocketChannel的選項
.option(ChannelOption.SO_BACKLOG, 128)
//配置子通道也就是SocketChannel的選項
.childOption(ChannelOption.SO_KEEPALIVE, true);
//綁定並偵聽某個端口
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
//如何沒有客戶端連接就會關閉Channel和兩個線程池
channelFuture.channel().closeFuture().sync();
} finally {
/**
* 關閉線程池
*/
workGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 10000;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
}
new TCPServerTrain(port).run();
}
}
代碼裏面的註釋已經很清楚了,沒有什麼可以細講的地方。下面的就是業務處理類,自己的業務處理主要放在這裏。代碼:
package nettytrain;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import network_train.ARPojo;
import network_train.ARSwitch;
/**
* TCPServerHandler.java
* Description: 主要的業務處理類
*
* @author Peng Shiquan
* @date 2020/6/18
*/
public class TCPServerHandler extends ChannelInboundHandlerAdapter {
/**
* Description: 通道的讀取操作方法
*
* @param ctx
* @param msg
* @return void
* @Author: Peng Shiquan
* @Date: 2020/6/19
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
ByteBuf recvmg = (ByteBuf) msg;
String line = recvmg.toString(CharsetUtil.UTF_8);
System.err.println("接收到消息" + line);
if (line.contains("BG") && line.contains("ED")) {
ARPojo arPojo = ARSwitch.LineSwitch(line);
System.err.println("轉換爲pojo對象" + arPojo.toString());
}
} finally {
// 釋放msg
ReferenceCountUtil.release(msg);
}
}
/**
* Description: 異常捕獲
*
* @param ctx
* @param cause
* @return void
* @Author: Peng Shiquan
* @Date: 2020/6/19
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
也是沒有什麼可以講的地方,這裏的業務處理我放在其他的地方了,所以這裏的代碼很少,每個人的業務不同,所以業務處理也不同。
下面就說說遇到的問題。就是通道讀取的方法,剛開始不知道怎麼處理msg,後來轉換成ByteBuf
,再轉換的String
,這個地方不知道處理的對不對。其他的問題就是這個代碼沒有考慮到粘包的現象,現在還沒有涉及到,所以沒有寫,後面慢慢補上。
就這樣吧,結束。