分別使用Java IO、NIO、Netty實現的一個Echo Server示例
分別使用Java IO、Java NIO、Netty來實現一個簡單的EchoServer(即原樣返回客戶端的輸入信息)。
Java IO
int port = 9000;
ServerSocket ss = new ServerSocket(port);
while (true) {
final Socket socket = ss.accept();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
BufferedInputStream in = new BufferedInputStream(
socket.getInputStream());
byte[] buf = new byte[1024];
int len = in.read(buf); // read message from client
String message = new String(buf, 0, len);
BufferedOutputStream out = new BufferedOutputStream(
socket.getOutputStream());
out.write(message.getBytes()); // echo to client
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
} 實際效果用telnet來演示,如下所示:
$ telnet 127.0.0.1 9000 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. hi hi 你好 你好
java io缺點:
需要為每個客戶端連接創建一個線程。
Java NIO
ServerSocketChannel ssChannel = ServerSocketChannel.open();
int port = 9001;
ssChannel.bind(new InetSocketAddress(port));
Selector selector = Selector.open();
ssChannel.configureBlocking(false);
ssChannel.register(selector, SelectionKey.OP_ACCEPT); //注冊監聽連接請求
while (true) {
selector.select();//阻塞 直到某個channel注冊的事件被觸發
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) { //客戶端連接請求
ServerSocketChannel ssc = (ServerSocketChannel) key
.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ); //注冊監聽客戶端輸入
}
if(key.isReadable()){ //客戶端輸入
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
sc.read(buffer);
buffer.flip();
sc.write(buffer);
}
}
keys.clear();
} 優點:
事件驅動 可通過一個線程來管理多個連接(channel)
但要注意 并不是任何場景都是NIO優于IO的。
Netty
public class NettyEchoServer {
public class EchoServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) { //ehco to client
ctx.write(msg);
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
private int port;
public NettyEchoServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(
new EchoServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(port).sync();
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully shut down your server.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 9002;
new NettyEchoServer(port).run();
}
} 上例摘自官方文檔。
優點:
事件驅動的概念比NIO更直觀 似乎僅需要繼承ChannelHandlerAdapter, 然后覆蓋相應方法即可。
參考文檔:
http://en.wikipedia.org/wiki/Non-blocking_I/O_(Java)
https://today.java.net/pub/a/today/2007/02/13/architecture-of-highly-scalable-nio-server.html
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!