1. 程式人生 > >【Java網路程式設計】:Netty實現OIO和NIO

【Java網路程式設計】:Netty實現OIO和NIO

承接上文:https://blog.csdn.net/hxcaifly/article/details/85274664

前言

單純地使用Java JDK來實現網路NIO是一件開發成本非常高的事情。然而,Netty 為它所有的傳輸實現提供了一個通用API,這使得這種轉換比你直接使用JDK所能夠達到的簡單得多。所產生的程式碼不會被實現的細節所汙染,而你也不需要在你的整個程式碼庫上進行廣泛的重構。簡而言之,你可以將時間花在其他更有成效的事情上。

1. Netty實現OIO

Netty實現OIO程式碼:

package chx.net.demo;

import io.
netty.bootstrap.ServerBootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.oio.OioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.oio.OioServerSocketChannel; import java.net.InetSocketAddress;
import java.nio.charset.Charset; public class NettyOioServer { public void server(int port) throws Exception { final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"))); EventLoopGroup group = new OioEventLoopGroup
(); try { // 1.建立 ServerBootstrap ServerBootstrap b = new ServerBootstrap(); b.group(group) // 2.使用 OioEventLoopGroup以允許阻塞模式(舊的I/O) .channel(OioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) // 3.指定 ChannelInitializer,對於每個已接受的連線都呼叫它 .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( // 4.新增一個 ChannelInboundHandlerAdapter以攔截和處理事件 new ChannelInboundHandlerAdapter() { @Override public void channelActive( ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(buf.duplicate()) .addListener( //5.將訊息寫到客戶端,並新增 ChannelFutureListener,以便訊息一被寫完就關閉連線 ChannelFutureListener.CLOSE); } }); } }); // 6.繫結伺服器以接受連線 ChannelFuture f = b.bind().sync(); f.channel().closeFuture().sync(); } finally { // 7.釋放所有的資源 group.shutdownGracefully().sync(); } } }

接下來,我們使用Netty 和非阻塞I/O 來實現同樣的邏輯。

2. 非阻塞的Netty 版本

package chx.net.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

 
public class NettyNioServer {
    public void server(int port) throws Exception {
        final ByteBuf buf =
                Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n",
                        Charset.forName("UTF-8")));
        // 1.為非阻塞模式使用NioEventLoopGroup
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            // 2.建立ServerBootstrap
            ServerBootstrap b = new ServerBootstrap();
            b.group(group).channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    // 3.指定 ChannelInitializer,對於每個已接受的連線都呼叫它
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                                      @Override
                                      public void initChannel(SocketChannel ch)
                                              throws Exception {
                                              ch.pipeline().addLast(
                                                 // 3.新增 ChannelInboundHandlerAdapter以接收和處理事件
                                                  new ChannelInboundHandlerAdapter() {
                                                      @Override
                                                      public void channelActive(
                                                              // 4.將訊息寫到客戶端,並新增ChannelFutureListener,
                                                              // 5.以便訊息一被寫完就關閉連線
                                                              ChannelHandlerContext ctx) throws Exception {
                                                                ctx.writeAndFlush(buf.duplicate())
                                                                  .addListener(
                                                                          ChannelFutureListener.CLOSE);
                                                      }
                                                  });
                                      }
                                  }
                    );
            // 6.繫結伺服器以接受連線
            ChannelFuture f = b.bind().sync();
            f.channel().closeFuture().sync();
        } finally {
            // 7.釋放所有的資源
            group.shutdownGracefully().sync();
        }
    }
}

可以看出,Netty實現OIO和NIO的程式碼很類似,主要是EventLoopGroup不同。Netty自己內部做的邏輯封裝減去了我們很大的開發成本。