一、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步骤