Java NIO框架Netty簡單使用
阿新 • • 發佈:2019-01-05
之前寫了一篇文章:Java 網路IO程式設計總結(BIO、NIO、AIO均含完整例項程式碼),介紹瞭如何使用Java原生IO支援進行網路程式設計,本文介紹一種更為簡單的方式,即Java NIO框架。
Netty是業界最流行的NIO框架之一,具有良好的健壯性、功能、效能、可定製性和可擴充套件性。同時,它提供的十分簡單的API,大大簡化了我們的網路程式設計。
同Java IO介紹的文章一樣,本文所展示的例子,實現了一個相同的功能。
1、服務端
Server:
package com.anxpp.io.calculator.netty; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; public class Server { private int port; public Server(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) .option(ChannelOption.SO_BACKLOG, 1024) .childOption(ChannelOption.SO_KEEPALIVE, true) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ServerHandler()); } }); ChannelFuture f = b.bind(port).sync(); System.out.println("伺服器開啟:"+port); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 9090; } new Server(port).run(); } }
ServerHandler:
package com.anxpp.io.calculator.netty; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import java.io.UnsupportedEncodingException; import com.anxpp.io.utils.Calculator; public class ServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException { ByteBuf in = (ByteBuf) msg; byte[] req = new byte[in.readableBytes()]; in.readBytes(req); String body = new String(req,"utf-8"); System.out.println("收到客戶端訊息:"+body); String calrResult = null; try{ calrResult = Calculator.Instance.cal(body).toString(); }catch(Exception e){ calrResult = "錯誤的表示式:" + e.getMessage(); } ctx.write(Unpooled.copiedBuffer(calrResult.getBytes())); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } /** * 異常處理 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } }
2、客戶端
Client:
package com.anxpp.io.calculator.netty; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import java.util.Scanner; public class Client implements Runnable{ static ClientHandler client = new ClientHandler(); public static void main(String[] args) throws Exception { new Thread(new Client()).start(); @SuppressWarnings("resource") Scanner scanner = new Scanner(System.in); while(client.sendMsg(scanner.nextLine())); } @Override public void run() { String host = "127.0.0.1"; int port = 9090; EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(client); } }); ChannelFuture f = b.connect(host, port).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); } } }
ClientHandler:
package com.anxpp.io.calculator.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.UnsupportedEncodingException;
public class ClientHandler extends ChannelInboundHandlerAdapter {
ChannelHandlerContext ctx;
/**
* tcp鏈路簡歷成功後呼叫
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
}
public boolean sendMsg(String msg){
System.out.println("客戶端傳送訊息:"+msg);
byte[] req = msg.getBytes();
ByteBuf m = Unpooled.buffer(req.length);
m.writeBytes(req);
ctx.writeAndFlush(m);
return msg.equals("q")?false:true;
}
/**
* 收到伺服器訊息後呼叫
* @throws UnsupportedEncodingException
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req,"utf-8");
System.out.println("伺服器訊息:"+body);
}
/**
* 發生異常時呼叫
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
3、用於計算的工具類
- package com.anxpp.io.utils;
- import javax.script.ScriptEngine;
- import javax.script.ScriptEngineManager;
- import javax.script.ScriptException;
- publicenumCalculator{
- Instance;
- privatefinalstaticScriptEngine jse =newScriptEngineManager().getEngineByName("JavaScript");
- publicObject cal(String expression)throwsScriptException{
- return jse.eval(expression);
- }
- }
4、測試
分別啟動服務端和客戶端,然後再客戶端控制檯輸入表示式:
- 1+5+5+5+5+5
- 客戶端傳送訊息:1+5+5+5+5+5
- 伺服器訊息:26
- 156158*458918+125615
- 客戶端傳送訊息:156158*458918+125615
- 伺服器訊息:7.1663842659E10
- 1895612+555+5+5+5+5+5+5+5-5*4/4
- 客戶端傳送訊息:1895612+555+5+5+5+5+5+5+5-5*4/4
- 伺服器訊息:1896197
可以看到服務端返回的結果。
檢視服務端控制檯:
- 伺服器開啟:9090
- 收到客戶端訊息:1+5+5+5+5+5
- 收到客戶端訊息:156158*458918+125615
- 收到客戶端訊息:1895612+555+5+5+5+5+5+5+5-5*4/4
5、更多
相關文章:
後續會繼續更新Netty相關內容,直到一個簡陋的通訊伺服器完成。