【Java網路程式設計】:Netty實現OIO和NIO
阿新 • • 發佈:2019-01-01
承接上文: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自己內部做的邏輯封裝減去了我們很大的開發成本。