preface
In the last section, we walked you through the basic uses of NIO in Java. As we all know, we use Netty mostly for its NIO. So in this section, we will also write a Netty based on the same functionality as the last section for comparison.
1. The service side
-
NioServer
public class NioServer {
public static void main(String[] args) {
int port = 8080;
ServerBootstrap serverBootstrap = new ServerBootstrap();
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(newNioServerHandler()); }}); ChannelFuture bind = serverBootstrap.bind(port);try {
bind.channel().closeFuture().sync();
} catch(InterruptedException e) { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }}}Copy the code
Here is the entry code for the Netty server, which is slightly more than the Java server, but can be divided into three parts:
-
Create ServerBootstrap, EventLoopGroup
-
Configure related configurations
-
Bind ports and close gracefully in case of an exception
-
NioServerHandler
public class NioServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "utf-8"); System.out.println("server received :" + body); ByteBuf resp = Unpooled.copiedBuffer(body.getBytes(StandardCharsets.UTF_8)); ctx.write(resp); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); }}Copy the code
Above is the code that handles the sending of messages by the server. Compared to Java’s processing logic, the code logic here is shockingly small. Basically, two methods are implemented to complete the logic of receiving and sending messages. Boy, how much performance must be deducted just by the amount of code left over.
2. The client
-
NioClient
public class NioClient {
public static void main(String[] args) {
Bootstrap bootstrap = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_BACKLOG, 1024)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(newNioClientHandler()); }}); ChannelFuture channelFuture = bootstrap.connect("localhost".8080);
try {
channelFuture.channel().closeFuture().sync();
} catch(InterruptedException e) { group.shutdownGracefully(); }}}Copy the code
Above is the code for the Netty client. As you can see, Bootstrap is basically the same as the server code.
-
NioClientHandler
public class NioClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Scanner scanner = new Scanner(System.in); System.out.println("Please enter the message to send."); String message = scanner.next(); byte[] req = message.getBytes(StandardCharsets.UTF_8); ByteBuf buf = Unpooled.buffer(req.length); buf.writeBytes(req); ctx.writeAndFlush(buf); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "utf-8"); System.out.println("client received :"+ body); }}Copy the code
The same is true here, where the code is minimal compared to the Java client’s verbose SelectionKey logic.
In the next section, we’ll look at the source code and see how Netty encapsulates Java’s NIO code.