Netty编程之HelloWorld
通过Netty的HelloWorld与NIO的HelloWord进行对比
分析一下两这个开发的复杂度,来证明Netty的意义
既然有了NIO,为什么还需要Netty
可以发现,用NIO编程非常复杂,使用Netty编程可以简化开发。
1
Netty服务器端开发
public class TimeServer {
public void bind(int port) {
//配置服务器端NIO线程组
//NioEventLoopGroup是个线程组,包含了一组NIO线程,处理网络事件,实际上就是Reactor线程组
try (EventLoopGroup bossLoopGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup()){
//netty用于启动NIO服务端的启动类,目的是降低NIO开发的复杂度
ServerBootstrap bootstrap = new ServerBootstrap();
//功能类似于NIO中的ServerSocketChannel
bootstrap.group(bossLoopGroup, workerGroup).channel(NioServerSocketChannel.class)
//配置NioServerSocketChannel的参数
.option(ChannelOption.SO_BACKLOG, 1024)
//绑定事件的处理类ChildChannelHandler
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeServerHandler());
}
});
//绑定端口,同步等待绑定操作完成
ChannelFuture channelFuture = bootstrap.bind(port).sync();
//等待服务器监听端口关闭
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int port = 8888;
new TimeServer().bind(port);
}
}
服务器端处理类ChildChannelHandler具体处理逻辑如下:
public class TimeServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//类似NIO中的ByteBuffer
ByteBuf buf = (ByteBuf) msg;
//获取缓冲区可读字节数
byte[] req = new byte[buf.readableBytes()];
//缓冲区中的字节复制到字节数组
buf.readBytes(req);
String body = new String(req);
System.out.println("收到输入:" + body);
ByteBuf response = Unpooled.copiedBuffer(("当前时间:" + new Date()).getBytes());
//并不是直接把消息发送到SocketChannel中,只是把消息发送到缓冲数组,通过flush方法将消息发到SocketChannel
ctx.write(response);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
//将消息发送队列中的消息写入SocketChannel中,发送到对方
//防止频繁的唤醒Selector进行消息发送
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
//发生异常关闭ChannelHandlerContext等资源
ctx.close();
}
}
2
Netty客户端开发
public class TimeClient {
public void connect(int port, String host) {
try (EventLoopGroup eventLoopGroup = new NioEventLoopGroup()){
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
//异步链接操作
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
//等待客户端
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int port = 8888;
new TimeClient().connect(port, "127.0.0.1");
}
}
客户端处理类TimeClientHandler具体处理逻辑如下:
public class TimeClientHandler extends ChannelHandlerAdapter {
private final ByteBuf firstMessage;
public TimeClientHandler() {
byte[] req = "hello world".getBytes();
firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(firstMessage);
}
/**
* 读取并打印消息
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] resp = new byte[buf.readableBytes()];
buf.readBytes(resp);
String body = new String(resp);
System.out.println(body);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
总结
可以发现,相比于直接用NIO开发,netty代码更加简洁,开发难度更低,扩展性更好。
本公众号后续文章将介绍Netty是如何处理TCP粘包和拆包等问题的,敬请关注