標籤:netty
netty 最新版本是netty-5.0.0.Alpha1,去年10月份發布的,至今沒有發新版本,估計這個版本還是比較穩定. 整包下載,裡麵包含一個 netty-example-5.0.0.Alpha1-sources.jar檔案,提供了比較豐富的example例子,多看幾遍還是非常有收穫的,這裡記錄下.
先來看下channelHandler的兩個不同繼承:
方式一:直接從ChannelHandlerAdapter類裡繼承,讀取操作從channelRead方法裡執行
@Sharablepublic class EchoServerHandler extends ChannelHandlerAdapter { private static final Logger logger = Logger.getLogger( EchoServerHandler.class.getName()); @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.write(msg); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // Close the connection when an exception is raised. logger.log(Level.WARNING, "Unexpected exception from downstream.", cause); ctx.close(); }}
方式二:繼承至SimpleChannelInboundHandler類,讀取操作從方法messageReceived()裡執行
public class FactorialServerHandler extendsSimpleChannelInboundHandler<BigInteger> {private static final Logger logger = Logger.getLogger(FactorialServerHandler.class.getName());private BigInteger lastMultiplier = new BigInteger("1");private BigInteger factorial = new BigInteger("1");@Overridepublic void messageReceived(ChannelHandlerContext ctx, BigInteger msg)throws Exception {// Calculate the cumulative factorial and send it to the client.System.out.println("server msg:" + msg);lastMultiplier = msg;factorial = factorial.multiply(msg);ctx.writeAndFlush(factorial);}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {Formatter fmt = new Formatter();logger.info(fmt.format("Factorial of %,d is: %,d", lastMultiplier,factorial).toString());fmt.close();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {logger.log(Level.WARNING, "Unexpected exception from downstream.",cause);ctx.close();}}
區別可以從SimpleChannelInboundHandler類的解說文字看出,
SimpleChannelInboundHandler : ChannelHandler which allows to explicit only handle a specific type of messages. 也就是可以操作指定類型的資訊.
接著看下 io.netty.example.factorial 這個包, 內容主要描述用戶端向服務端發數字,服務端返回數位階乘給用戶端,業務比較簡單.
編解碼操作涉及到的類,BigIntegerDecoder與NumberEncoder都是自訂的
pipeline.addLast("decoder", new BigIntegerDecoder());
pipeline.addLast("encoder", new NumberEncoder());
用戶端有這麼一段代碼:
ChannelFuture future = null;for (int i = 0; i < 4096 && next <= count; i++) {future = ctx.write(Integer.valueOf(next));next++;}if (next <= count) {assert future != null;future.addListener(numberSender);}ctx.flush();
服務端代碼:
@Overridepublic void messageReceived(ChannelHandlerContext ctx, BigInteger msg)throws Exception {// Calculate the cumulative factorial and send it to the client.System.out.println("server msg:" + msg);lastMultiplier = msg;factorial = factorial.multiply(msg);ctx.writeAndFlush(factorial);}
看了用戶端代碼覺得代碼在最後才flush的,所以服務端應該只收到一條訊息,messageReceived方法應該只調用一次,結果是messageReceived方法調用次數與用戶端發送次數一致. 有點奇怪. 看了下BigIntegerDecoder解碼類操作才探索服務端的確只收到了一條訊息,但是解碼器解碼成了多個對象(BigIntegerDecoder 類的decode方法被其父類ByteToMessageDecoder的callDecode方法反覆讀取同一條訊息的ByteBuf,直到讀完.),最後多次調用messageReceived方法.
以後如果自己寫編解碼類完全可以參考BigIntegerDecoder與NumberEncoder這兩個類來.
最後來看下http的幾個ChannelHandler
服務端:
pipeline.addLast("decoder", new HttpRequestDecoder()); pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); pipeline.addLast("encoder", new HttpResponseEncoder()); pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
用戶端:
p.addLast("codec", new HttpClientCodec());p.addLast("aggregator", new HttpObjectAggregator(1048576));
剛看到時候覺得奇怪怎麼服務端與用戶端編解碼方式不一樣, 看下httpClientCoder類的說明(A combination of HttpRequestEncoder and HttpResponseDecoder which enables easier client side HTTP implementation),自然就懂了.
HttpObjectAggregator 瞭解這個handler先看段代碼:
@Override protected void messageReceived(ChannelHandlerContext ctx, Object msg) { if (msg instanceof HttpRequest) { } if (msg instanceof HttpContent) { } }
一般http請求或者響應,解碼器都將其解碼成為多個訊息對象,主要是httpRequest/httpResponse, httpcontent, lastHttpContent.然後反覆調用messageReceive這個方法,
HttpObjectAggregator 這個handler就是將同一個http請求或響應的多個訊息對象變成一個 fullHttpRequest完整的訊息對象.
netty 學習記錄二