一、Netty的常見應用場景
- 構建HTTP服務器
- Socket開發
- 基於HTTP長連接開發
二、Socket開發示例
1. 服務端開發
1.1 主函數
public class Server {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
ChannelFuture future = bootstrap.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerInitializer())
.bind(8899)
.sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
1.2 Initializer類
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ChannelHandle());
}
}
1.3 Handle類
public class ChannelHandle extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("請求地址:" + ctx.channel().remoteAddress() + ", 請求消息:" + msg);
ctx.writeAndFlush("From server: " + msg + ", " + UUID.randomUUID());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
2. 客戶端開發
2.1 主函數
public class Client {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.handler(new ClientInitializer());
ChannelFuture future = bootstrap.connect("localhost", 8899);
future.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
2.1 Initializer類
public class ClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new ChannelHandle());
}
}
2.3 Handle類
public class ChannelHandle extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("remote address: " + ctx.channel().remoteAddress());
System.out.println("from server: " + msg);
ctx.writeAndFlush("from client: " + LocalDateTime.now());
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("start ...");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
3. 執行結果
- 服務端
請求地址:/127.0.0.1:50796, 請求消息:from client: 2019-12-01T23:06:06.953
- 客戶端
在服務端和客戶端都啓動後會發現服務端不斷的接收到客戶端的請求,客戶端不斷地響應着服務端的返回
4. 執行流程
- 服務端啓動
- 客戶端啓動,執行ChannelHandle中的channelActive方法,向服務端發送消息
- 服務端的ChannelHandle中的channelRead0進行響應處理,並向客戶端響應消息
- 客戶端的ChannelHandle中的channelRead0響應服務端的響應,並向服務端發送消息
- 重複3,4步驟