From 18c6f7e0dc5dbf65669e2f5db0ba8de4a1486a62 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Fri, 21 Apr 2017 01:32:07 +0800 Subject: [PATCH 01/75] = tweak with alignments --- .../java/nia/chapter1/BlockingIoExample.java | 4 ++ .../java/nia/chapter1/ConnectExample.java | 11 +++- .../main/java/nia/chapter1/package-info.java | 4 +- .../java/nia/chapter10/CharToByteEncoder.java | 4 +- .../nia/chapter10/IntegerToStringDecoder.java | 4 +- .../nia/chapter10/IntegerToStringEncoder.java | 1 - .../chapter10/SafeByteToMessageDecoder.java | 1 - .../java/nia/chapter10/ToIntegerDecoder2.java | 3 +- .../chapter10/WebSocketConvertHandler.java | 59 +++++++++---------- .../main/java/nia/chapter10/package-info.java | 2 +- .../ChunkedWriteHandlerInitializer.java | 11 ++-- .../nia/chapter11/CmdHandlerInitializer.java | 4 +- .../nia/chapter11/FileRegionWriteHandler.java | 24 ++++---- .../chapter11/HttpAggregatorInitializer.java | 2 + .../chapter11/HttpCompressionInitializer.java | 6 +- .../nia/chapter11/HttpsCodecInitializer.java | 3 + .../IdleStateHandlerInitializer.java | 13 ++-- .../nia/chapter11/LengthBasedInitializer.java | 5 +- .../LineBasedHandlerInitializer.java | 5 +- .../nia/chapter11/MarshallingInitializer.java | 6 +- .../nia/chapter11/ProtoBufInitializer.java | 4 +- .../nia/chapter11/SslChannelInitializer.java | 5 +- .../chapter11/WebSocketServerInitializer.java | 24 ++++---- .../main/java/nia/chapter11/package-info.java | 2 +- .../main/java/nia/chapter12/ChatServer.java | 8 +-- .../nia/chapter12/ChatServerInitializer.java | 3 +- .../nia/chapter12/HttpRequestHandler.java | 29 +++++---- .../java/nia/chapter12/SecureChatServer.java | 7 ++- .../SecureChatServerInitializer.java | 3 +- .../chapter12/TextWebSocketFrameHandler.java | 7 ++- .../src/main/java/nia/chapter13/LogEvent.java | 2 +- .../nia/chapter13/LogEventBroadcaster.java | 8 +-- .../java/nia/chapter13/LogEventDecoder.java | 8 +-- .../java/nia/chapter13/LogEventEncoder.java | 4 +- .../java/nia/chapter13/LogEventHandler.java | 4 +- .../java/nia/chapter13/LogEventMonitor.java | 28 ++++----- .../nia/chapter2/echoclient/EchoClient.java | 32 +++++----- .../echoclient/EchoClientHandler.java | 13 +--- .../echoserver/EchoServerHandler.java | 2 +- .../chapter4/ChannelOperationExamples.java | 8 ++- .../java/nia/chapter4/NettyNioServer.java | 6 +- .../java/nia/chapter4/NettyOioServer.java | 3 +- .../java/nia/chapter4/PlainNioServer.java | 1 - .../java/nia.chapter5/ByteBufExamples.java | 28 +++++---- .../main/java/nia.chapter5/package-info.java | 2 +- .../nia/chapter6/ModifyChannelPipeline.java | 3 + .../chapter6/OutboundExceptionHandler.java | 1 - .../main/java/nia/chapter6/WriteHandler.java | 2 - .../main/java/nia/chapter6/WriteHandlers.java | 2 +- .../main/java/nia/chapter6/package-info.java | 2 +- .../java/nia/chapter7/EventLoopExamples.java | 5 -- .../java/nia/chapter7/ScheduleExamples.java | 40 ++++++------- .../main/java/nia/chapter7/package-info.java | 2 +- .../java/nia/chapter8/BootstrapClient.java | 16 +++-- .../chapter8/BootstrapDatagramChannel.java | 28 ++++----- .../java/nia/chapter8/BootstrapServer.java | 3 +- .../java/nia/chapter8/GracefulShutdown.java | 6 +- .../nia/chapter8/InvalidBootstrapClient.java | 15 +++-- .../main/java/nia/chapter8/package-info.java | 2 +- .../java/nia/chapter9/AbsIntegerEncoder.java | 7 +-- .../test/chapter9/FrameChunkDecoderTest.java | 3 +- 61 files changed, 279 insertions(+), 271 deletions(-) diff --git a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java index 1be636a5..94cf0bc1 100644 --- a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java +++ b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java @@ -13,6 +13,10 @@ * Listing 1.1 Blocking I/O example */ public class BlockingIoExample { + + /** + * Listing 1.1 Blocking I/O example + * */ public void serve(int portNumber) throws IOException { ServerSocket serverSocket = new ServerSocket(portNumber); Socket clientSocket = serverSocket.accept(); diff --git a/chapter1/src/main/java/nia/chapter1/ConnectExample.java b/chapter1/src/main/java/nia/chapter1/ConnectExample.java index 8f41b7cc..fa3ab7cf 100644 --- a/chapter1/src/main/java/nia/chapter1/ConnectExample.java +++ b/chapter1/src/main/java/nia/chapter1/ConnectExample.java @@ -5,6 +5,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; +import io.netty.channel.socket.nio.NioSocketChannel; import java.net.InetSocketAddress; import java.nio.charset.Charset; @@ -13,11 +14,19 @@ * Created by kerr. * * Listing 1.3 Asynchronous connect + * * Listing 1.4 Callback in action */ public class ConnectExample { + private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); - public static void connect(Channel channel) { + /** + * Listing 1.3 Asynchronous connect + * + * Listing 1.4 Callback in action + * */ + public static void connect() { + Channel channel = CHANNEL_FROM_SOMEWHERE; //reference form somewhere // Does not block ChannelFuture future = channel.connect( new InetSocketAddress("192.168.0.1", 25)); diff --git a/chapter1/src/main/java/nia/chapter1/package-info.java b/chapter1/src/main/java/nia/chapter1/package-info.java index d16877da..8b659ac8 100644 --- a/chapter1/src/main/java/nia/chapter1/package-info.java +++ b/chapter1/src/main/java/nia/chapter1/package-info.java @@ -5,8 +5,8 @@ * * Listing 1.2 ChannelHandler triggered by a callback {@link nia.chapter1.ConnectHandler} * - * Listing 1.3 Asynchronous connect {@link nia.chapter1.ConnectExample#connect(io.netty.channel.Channel)} + * Listing 1.3 Asynchronous connect {@link nia.chapter1.ConnectExample#connect()} * - * Listing 1.4 Callback in action {@link nia.chapter1.ConnectExample#connect(io.netty.channel.Channel)} + * Listing 1.4 Callback in action {@link nia.chapter1.ConnectExample#connect()} */ package nia.chapter1; \ No newline at end of file diff --git a/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java b/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java index 46a261b1..966b658b 100644 --- a/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java +++ b/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java @@ -9,8 +9,8 @@ * * @author Norman Maurer */ -public class CharToByteEncoder - extends MessageToByteEncoder { +public class CharToByteEncoder extends + MessageToByteEncoder { @Override public void encode(ChannelHandlerContext ctx, Character msg, ByteBuf out) throws Exception { diff --git a/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java b/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java index 1921250e..bccbf693 100644 --- a/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java +++ b/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java @@ -10,8 +10,8 @@ * * @author Norman Maurer */ -public class IntegerToStringDecoder - extends MessageToMessageDecoder { +public class IntegerToStringDecoder extends + MessageToMessageDecoder { @Override public void decode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { diff --git a/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java b/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java index 55c5b94a..6c6390da 100644 --- a/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java +++ b/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java @@ -12,7 +12,6 @@ */ public class IntegerToStringEncoder extends MessageToMessageEncoder { - @Override public void encode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { diff --git a/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java b/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java index d5738ed7..6328cd28 100644 --- a/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java +++ b/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java @@ -15,7 +15,6 @@ public class SafeByteToMessageDecoder extends ByteToMessageDecoder { private static final int MAX_FRAME_SIZE = 1024; - @Override public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { diff --git a/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java b/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java index f03d28ae..52a0157a 100644 --- a/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java +++ b/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java @@ -11,8 +11,7 @@ * * @author Norman Maurer */ -public class ToIntegerDecoder2 - extends ReplayingDecoder { +public class ToIntegerDecoder2 extends ReplayingDecoder { @Override public void decode(ChannelHandlerContext ctx, ByteBuf in, diff --git a/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java b/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java index 7579700b..dc5a3f52 100644 --- a/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java +++ b/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java @@ -15,36 +15,35 @@ */ @Sharable public class WebSocketConvertHandler extends - MessageToMessageCodec { - @Override - protected void encode(ChannelHandlerContext ctx, - WebSocketConvertHandler.MyWebSocketFrame msg, - List out) throws Exception { - ByteBuf payload = msg.getData().duplicate().retain(); - switch (msg.getType()) { - case BINARY: - out.add(new BinaryWebSocketFrame(payload)); - break; - case TEXT: - out.add(new TextWebSocketFrame(payload)); - break; - case CLOSE: - out.add(new CloseWebSocketFrame(true, 0, payload)); - break; - case CONTINUATION: - out.add(new ContinuationWebSocketFrame(payload)); - break; - case PONG: - out.add(new PongWebSocketFrame(payload)); - break; - case PING: - out.add(new PingWebSocketFrame(payload)); - break; - default: - throw new IllegalStateException( - "Unsupported websocket msg " + msg); - } + MessageToMessageCodec { + @Override + protected void encode(ChannelHandlerContext ctx, + WebSocketConvertHandler.MyWebSocketFrame msg, + List out) throws Exception { + ByteBuf payload = msg.getData().duplicate().retain(); + switch (msg.getType()) { + case BINARY: + out.add(new BinaryWebSocketFrame(payload)); + break; + case TEXT: + out.add(new TextWebSocketFrame(payload)); + break; + case CLOSE: + out.add(new CloseWebSocketFrame(true, 0, payload)); + break; + case CONTINUATION: + out.add(new ContinuationWebSocketFrame(payload)); + break; + case PONG: + out.add(new PongWebSocketFrame(payload)); + break; + case PING: + out.add(new PingWebSocketFrame(payload)); + break; + default: + throw new IllegalStateException( + "Unsupported websocket msg " + msg);} } @Override diff --git a/chapter10/src/main/java/nia/chapter10/package-info.java b/chapter10/src/main/java/nia/chapter10/package-info.java index fb45e03a..d5f47fa7 100644 --- a/chapter10/src/main/java/nia/chapter10/package-info.java +++ b/chapter10/src/main/java/nia/chapter10/package-info.java @@ -5,7 +5,7 @@ * * Listing 10.2 Class ToIntegerDecoder2 extends ReplayingDecoder {@link nia.chapter10.ToIntegerDecoder2} * - * Listing 10.3 Class IntegerToStringDecoder {@link nia.chapter10.IntegerToStringEncoder} + * Listing 10.3 Class IntegerToStringDecoder {@link nia.chapter10.IntegerToStringDecoder} * * Listing 10.4 TooLongFrameException {@link nia.chapter10.SafeByteToMessageDecoder} * diff --git a/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java index d4ebf0a5..fcde7c2d 100644 --- a/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java @@ -15,13 +15,14 @@ * @author Norman Maurer */ public class ChunkedWriteHandlerInitializer - extends ChannelInitializer { + extends ChannelInitializer { private final File file; private final SslContext sslCtx; public ChunkedWriteHandlerInitializer(File file, SslContext sslCtx) { this.file = file; this.sslCtx = sslCtx; } + @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); @@ -29,14 +30,16 @@ protected void initChannel(Channel ch) throws Exception { pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new WriteStreamHandler()); } + public final class WriteStreamHandler - extends ChannelInboundHandlerAdapter { + extends ChannelInboundHandlerAdapter { + @Override public void channelActive(ChannelHandlerContext ctx) - throws Exception { + throws Exception { super.channelActive(ctx); ctx.writeAndFlush( - new ChunkedStream(new FileInputStream(file))); + new ChunkedStream(new FileInputStream(file))); } } } diff --git a/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java index 470df607..1ab893fc 100644 --- a/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java @@ -11,7 +11,6 @@ */ public class CmdHandlerInitializer extends ChannelInitializer { private static final byte SPACE = (byte)' '; - @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); @@ -41,9 +40,10 @@ public static final class CmdDecoder extends LineBasedFrameDecoder { public CmdDecoder(int maxLength) { super(maxLength); } + @Override protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) - throws Exception { + throws Exception { ByteBuf frame = (ByteBuf) super.decode(ctx, buffer); if (frame == null) { return null; diff --git a/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java b/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java index b84bc62a..13f65b39 100644 --- a/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java +++ b/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java @@ -17,22 +17,22 @@ public class FileRegionWriteHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(final ChannelHandlerContext ctx) throws Exception { - File file = FILE_FROM_SOMEWHERE; - Channel channel = CHANNEL_FROM_SOMEWHERE; + File file = FILE_FROM_SOMEWHERE; //get reference from somewhere + Channel channel = CHANNEL_FROM_SOMEWHERE; //get reference from somewhere //... FileInputStream in = new FileInputStream(file); FileRegion region = new DefaultFileRegion( in.getChannel(), 0, file.length()); channel.writeAndFlush(region).addListener( - new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) - throws Exception { - if (!future.isSuccess()) { - Throwable cause = future.cause(); - // Do something - } - } - }); + new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) + throws Exception { + if (!future.isSuccess()) { + Throwable cause = future.cause(); + // Do something + } + } + }); } } diff --git a/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java index 75d5a06b..83944191 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java @@ -14,9 +14,11 @@ */ public class HttpAggregatorInitializer extends ChannelInitializer { private final boolean isClient; + public HttpAggregatorInitializer(boolean isClient) { this.isClient = isClient; } + @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); diff --git a/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java index 0c616cbc..9c6ece23 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java @@ -15,20 +15,22 @@ */ public class HttpCompressionInitializer extends ChannelInitializer { private final boolean isClient; + public HttpCompressionInitializer(boolean isClient) { this.isClient = isClient; } + @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (isClient) { pipeline.addLast("codec", new HttpClientCodec()); pipeline.addLast("decompressor", - new HttpContentDecompressor()); + new HttpContentDecompressor()); } else { pipeline.addLast("codec", new HttpServerCodec()); pipeline.addLast("compressor", - new HttpContentCompressor()); + new HttpContentCompressor()); } } } diff --git a/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java index 185bb65a..78e1f7ac 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java @@ -18,15 +18,18 @@ public class HttpsCodecInitializer extends ChannelInitializer { private final SslContext context; private final boolean isClient; + public HttpsCodecInitializer(SslContext context, boolean isClient) { this.context = context; this.isClient = isClient; } + @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); SSLEngine engine = context.newEngine(ch.alloc()); pipeline.addFirst("ssl", new SslHandler(engine)); + if (isClient) { pipeline.addLast("codec", new HttpClientCodec()); } else { diff --git a/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java index a9861644..f00b8e05 100644 --- a/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java @@ -14,7 +14,8 @@ * * @author Norman Maurer */ -public class IdleStateHandlerInitializer extends ChannelInitializer { +public class IdleStateHandlerInitializer extends ChannelInitializer + { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); @@ -24,17 +25,17 @@ protected void initChannel(Channel ch) throws Exception { } public static final class HeartbeatHandler - extends ChannelInboundHandlerAdapter { + extends ChannelInboundHandlerAdapter { private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer( - "HEARTBEAT", CharsetUtil.ISO_8859_1)); + "HEARTBEAT", CharsetUtil.ISO_8859_1)); @Override public void userEventTriggered(ChannelHandlerContext ctx, - Object evt) throws Exception { + Object evt) throws Exception { if (evt instanceof IdleStateEvent) { ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()) - .addListener( - ChannelFutureListener.CLOSE_ON_FAILURE); + .addListener( + ChannelFutureListener.CLOSE_ON_FAILURE); } else { super.userEventTriggered(ctx, evt); } diff --git a/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java b/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java index 8e1088a7..a1d0fb14 100644 --- a/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java @@ -17,11 +17,12 @@ protected void initChannel(Channel ch) throws Exception { new LengthFieldBasedFrameDecoder(64 * 1024, 0, 8)); pipeline.addLast(new FrameHandler()); } + public static final class FrameHandler - extends SimpleChannelInboundHandler { + extends SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, - ByteBuf msg) throws Exception { + ByteBuf msg) throws Exception { // Do something with the frame } } diff --git a/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java index ae44ee48..652d020b 100644 --- a/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java @@ -11,7 +11,6 @@ */ public class LineBasedHandlerInitializer extends ChannelInitializer { - @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); @@ -20,10 +19,10 @@ protected void initChannel(Channel ch) throws Exception { } public static final class FrameHandler - extends SimpleChannelInboundHandler { + extends SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, - ByteBuf msg) throws Exception { + ByteBuf msg) throws Exception { // Do something with the data extracted from the frame } } diff --git a/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java b/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java index 8641f090..c027a629 100644 --- a/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java @@ -33,11 +33,11 @@ protected void initChannel(Channel channel) throws Exception { } public static final class ObjectHandler - extends SimpleChannelInboundHandler { + extends SimpleChannelInboundHandler { @Override public void channelRead0( - ChannelHandlerContext channelHandlerContext, - Serializable serializable) throws Exception { + ChannelHandlerContext channelHandlerContext, + Serializable serializable) throws Exception { // Do something } } diff --git a/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java b/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java index 6a2745b6..e5b77e06 100644 --- a/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java @@ -28,10 +28,10 @@ protected void initChannel(Channel ch) throws Exception { } public static final class ObjectHandler - extends SimpleChannelInboundHandler { + extends SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) - throws Exception { + throws Exception { // Do something with the object } } diff --git a/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java b/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java index 2f5dd0dd..55f95aac 100644 --- a/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java @@ -15,8 +15,9 @@ public class SslChannelInitializer extends ChannelInitializer { private final SslContext context; private final boolean startTls; + public SslChannelInitializer(SslContext context, - boolean startTls) { + boolean startTls) { this.context = context; this.startTls = startTls; } @@ -24,6 +25,6 @@ public SslChannelInitializer(SslContext context, protected void initChannel(Channel ch) throws Exception { SSLEngine engine = context.newEngine(ch.alloc()); ch.pipeline().addFirst("ssl", - new SslHandler(engine, startTls)); + new SslHandler(engine, startTls)); } } diff --git a/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java b/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java index a9698749..cbced5ef 100644 --- a/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java @@ -20,37 +20,37 @@ public class WebSocketServerInitializer extends ChannelInitializer { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline().addLast( - new HttpServerCodec(), - new HttpObjectAggregator(65536), - new WebSocketServerProtocolHandler("/websocket"), - new TextFrameHandler(), - new BinaryFrameHandler(), - new ContinuationFrameHandler()); + new HttpServerCodec(), + new HttpObjectAggregator(65536), + new WebSocketServerProtocolHandler("/websocket"), + new TextFrameHandler(), + new BinaryFrameHandler(), + new ContinuationFrameHandler()); } public static final class TextFrameHandler extends - SimpleChannelInboundHandler { + SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, - TextWebSocketFrame msg) throws Exception { + TextWebSocketFrame msg) throws Exception { // Handle text frame } } public static final class BinaryFrameHandler extends - SimpleChannelInboundHandler { + SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, - BinaryWebSocketFrame msg) throws Exception { + BinaryWebSocketFrame msg) throws Exception { // Handle binary frame } } public static final class ContinuationFrameHandler extends - SimpleChannelInboundHandler { + SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, - ContinuationWebSocketFrame msg) throws Exception { + ContinuationWebSocketFrame msg) throws Exception { // Handle continuation frame } } diff --git a/chapter11/src/main/java/nia/chapter11/package-info.java b/chapter11/src/main/java/nia/chapter11/package-info.java index a1666bd4..1f9c3a47 100644 --- a/chapter11/src/main/java/nia/chapter11/package-info.java +++ b/chapter11/src/main/java/nia/chapter11/package-info.java @@ -15,7 +15,7 @@ * * Listing 11.7 Sending heartbeats {@link nia.chapter11.IdleStateHandlerInitializer} * - * Listing 11.8 Handling line-delimited frames {@link nia.chapter11.LengthBasedInitializer} + * Listing 11.8 Handling line-delimited frames {@link nia.chapter11.LineBasedHandlerInitializer} * * Listing 11.9 Using a ChannelInitializer as a decoder installer {@link nia.chapter11.CmdHandlerInitializer} * diff --git a/chapter12/src/main/java/nia/chapter12/ChatServer.java b/chapter12/src/main/java/nia/chapter12/ChatServer.java index 7e3cff17..837e5811 100644 --- a/chapter12/src/main/java/nia/chapter12/ChatServer.java +++ b/chapter12/src/main/java/nia/chapter12/ChatServer.java @@ -20,15 +20,15 @@ */ public class ChatServer { private final ChannelGroup channelGroup = - new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); + new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); private final EventLoopGroup group = new NioEventLoopGroup(); private Channel channel; public ChannelFuture start(InetSocketAddress address) { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(group) - .channel(NioServerSocketChannel.class) - .childHandler(createInitializer(channelGroup)); + .channel(NioServerSocketChannel.class) + .childHandler(createInitializer(channelGroup)); ChannelFuture future = bootstrap.bind(address); future.syncUninterruptibly(); channel = future.channel(); @@ -36,7 +36,7 @@ public ChannelFuture start(InetSocketAddress address) { } protected ChannelInitializer createInitializer( - ChannelGroup group) { + ChannelGroup group) { return new ChatServerInitializer(group); } diff --git a/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java b/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java index 0b429e30..3316a8d8 100644 --- a/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java +++ b/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java @@ -14,8 +14,7 @@ * * @author Norman Maurer */ -public class ChatServerInitializer - extends ChannelInitializer { +public class ChatServerInitializer extends ChannelInitializer { private final ChannelGroup group; public ChatServerInitializer(ChannelGroup group) { diff --git a/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java b/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java index eb5803bf..b781cde0 100644 --- a/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java +++ b/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java @@ -15,22 +15,21 @@ * * @author Norman Maurer */ -public class HttpRequestHandler - extends SimpleChannelInboundHandler { +public class HttpRequestHandler extends SimpleChannelInboundHandler { private final String wsUri; private static final File INDEX; static { URL location = HttpRequestHandler.class - .getProtectionDomain() - .getCodeSource().getLocation(); + .getProtectionDomain() + .getCodeSource().getLocation(); try { String path = location.toURI() + "index.html"; path = !path.contains("file:") ? path : path.substring(5); INDEX = new File(path); } catch (URISyntaxException e) { throw new IllegalStateException( - "Unable to locate index.html", e); + "Unable to locate index.html", e); } } @@ -40,7 +39,7 @@ public HttpRequestHandler(String wsUri) { @Override public void channelRead0(ChannelHandlerContext ctx, - FullHttpRequest request) throws Exception { + FullHttpRequest request) throws Exception { if (wsUri.equalsIgnoreCase(request.getUri())) { ctx.fireChannelRead(request.retain()); } else { @@ -49,26 +48,26 @@ public void channelRead0(ChannelHandlerContext ctx, } RandomAccessFile file = new RandomAccessFile(INDEX, "r"); HttpResponse response = new DefaultHttpResponse( - request.getProtocolVersion(), HttpResponseStatus.OK); + request.getProtocolVersion(), HttpResponseStatus.OK); response.headers().set( - HttpHeaders.Names.CONTENT_TYPE, - "text/plain; charset=UTF-8"); + HttpHeaders.Names.CONTENT_TYPE, + "text/plain; charset=UTF-8"); boolean keepAlive = HttpHeaders.isKeepAlive(request); if (keepAlive) { response.headers().set( - HttpHeaders.Names.CONTENT_LENGTH, file.length()); + HttpHeaders.Names.CONTENT_LENGTH, file.length()); response.headers().set( HttpHeaders.Names.CONNECTION, - HttpHeaders.Values.KEEP_ALIVE); + HttpHeaders.Values.KEEP_ALIVE); } ctx.write(response); if (ctx.pipeline().get(SslHandler.class) == null) { ctx.write(new DefaultFileRegion( - file.getChannel(), 0, file.length())); + file.getChannel(), 0, file.length())); } else { ctx.write(new ChunkedNioFile(file.getChannel())); } ChannelFuture future = ctx.writeAndFlush( - LastHttpContent.EMPTY_LAST_CONTENT); + LastHttpContent.EMPTY_LAST_CONTENT); if (!keepAlive) { future.addListener(ChannelFutureListener.CLOSE); } @@ -77,12 +76,12 @@ public void channelRead0(ChannelHandlerContext ctx, private static void send100Continue(ChannelHandlerContext ctx) { FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); + HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); ctx.writeAndFlush(response); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) - throws Exception { + throws Exception { cause.printStackTrace(); ctx.close(); } diff --git a/chapter12/src/main/java/nia/chapter12/SecureChatServer.java b/chapter12/src/main/java/nia/chapter12/SecureChatServer.java index b2f4ee61..a7779ede 100644 --- a/chapter12/src/main/java/nia/chapter12/SecureChatServer.java +++ b/chapter12/src/main/java/nia/chapter12/SecureChatServer.java @@ -10,20 +10,23 @@ import java.net.InetSocketAddress; /** - * Listing 12.7 of Netty in Action + * Listing 12.7 Adding encryption to the ChatServer * * @author Norman Maurer */ public class SecureChatServer extends ChatServer { private final SslContext context; + public SecureChatServer(SslContext context) { this.context = context; } + @Override protected ChannelInitializer createInitializer( - ChannelGroup group) { + ChannelGroup group) { return new SecureChatServerInitializer(group, context); } + public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Please give port as argument"); diff --git a/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java b/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java index 9fcaad36..a4b669ac 100644 --- a/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java +++ b/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java @@ -15,7 +15,8 @@ public class SecureChatServerInitializer extends ChatServerInitializer { private final SslContext context; - public SecureChatServerInitializer(ChannelGroup group, SslContext context) { + public SecureChatServerInitializer(ChannelGroup group, + SslContext context) { super(group); this.context = context; } diff --git a/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java b/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java index da12cfb0..e781e9c6 100644 --- a/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java +++ b/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java @@ -21,9 +21,9 @@ public TextWebSocketFrameHandler(ChannelGroup group) { @Override public void userEventTriggered(ChannelHandlerContext ctx, - Object evt) throws Exception { + Object evt) throws Exception { if (evt == WebSocketServerProtocolHandler - .ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { + .ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { ctx.pipeline().remove(HttpRequestHandler.class); group.writeAndFlush(new TextWebSocketFrame( "Client " + ctx.channel() + " joined")); @@ -32,9 +32,10 @@ public void userEventTriggered(ChannelHandlerContext ctx, super.userEventTriggered(ctx, evt); } } + @Override public void channelRead0(ChannelHandlerContext ctx, - TextWebSocketFrame msg) throws Exception { + TextWebSocketFrame msg) throws Exception { group.writeAndFlush(msg.retain()); } } diff --git a/chapter13/src/main/java/nia/chapter13/LogEvent.java b/chapter13/src/main/java/nia/chapter13/LogEvent.java index 805d424b..6b375d36 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEvent.java +++ b/chapter13/src/main/java/nia/chapter13/LogEvent.java @@ -19,7 +19,7 @@ public LogEvent(String logfile, String msg) { } public LogEvent(InetSocketAddress source, long received, - String logfile, String msg) { + String logfile, String msg) { this.source = source; this.logfile = logfile; this.msg = msg; diff --git a/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java b/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java index 8b9ebb55..8ba1a017 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java @@ -25,8 +25,8 @@ public LogEventBroadcaster(InetSocketAddress address, File file) { group = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioDatagramChannel.class) - .option(ChannelOption.SO_BROADCAST, true) - .handler(new LogEventEncoder(address)); + .option(ChannelOption.SO_BROADCAST, true) + .handler(new LogEventEncoder(address)); this.file = file; } @@ -45,7 +45,7 @@ public void run() throws Exception { String line; while ((line = raf.readLine()) != null) { ch.writeAndFlush(new LogEvent(null, -1, - file.getAbsolutePath(), line)); + file.getAbsolutePath(), line)); } pointer = raf.getFilePointer(); raf.close(); @@ -69,7 +69,7 @@ public static void main(String[] args) throws Exception { } LogEventBroadcaster broadcaster = new LogEventBroadcaster( new InetSocketAddress("255.255.255.255", - Integer.parseInt(args[0])), new File(args[1])); + Integer.parseInt(args[0])), new File(args[1])); try { broadcaster.run(); } diff --git a/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java b/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java index f8fb2481..7abaaad9 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java @@ -21,13 +21,13 @@ protected void decode(ChannelHandlerContext ctx, throws Exception { ByteBuf data = datagramPacket.content(); int idx = data.indexOf(0, data.readableBytes(), - LogEvent.SEPARATOR); + LogEvent.SEPARATOR); String filename = data.slice(0, idx) - .toString(CharsetUtil.UTF_8); + .toString(CharsetUtil.UTF_8); String logMsg = data.slice(idx + 1, - data.readableBytes()).toString(CharsetUtil.UTF_8); + data.readableBytes()).toString(CharsetUtil.UTF_8); LogEvent event = new LogEvent(datagramPacket.sender(), - System.currentTimeMillis(), filename, logMsg); + System.currentTimeMillis(), filename, logMsg); out.add(event); } } diff --git a/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java b/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java index 336df0f6..ef02bb5c 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java @@ -23,11 +23,11 @@ public LogEventEncoder(InetSocketAddress remoteAddress) { @Override protected void encode(ChannelHandlerContext channelHandlerContext, - LogEvent logEvent, List out) throws Exception { + LogEvent logEvent, List out) throws Exception { byte[] file = logEvent.getLogfile().getBytes(CharsetUtil.UTF_8); byte[] msg = logEvent.getMsg().getBytes(CharsetUtil.UTF_8); ByteBuf buf = channelHandlerContext.alloc() - .buffer(file.length + msg.length + 1); + .buffer(file.length + msg.length + 1); buf.writeBytes(file); buf.writeByte(LogEvent.SEPARATOR); buf.writeBytes(msg); diff --git a/chapter13/src/main/java/nia/chapter13/LogEventHandler.java b/chapter13/src/main/java/nia/chapter13/LogEventHandler.java index 437d7fad..cd447d82 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventHandler.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventHandler.java @@ -13,14 +13,14 @@ public class LogEventHandler @Override public void exceptionCaught(ChannelHandlerContext ctx, - Throwable cause) throws Exception { + Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } @Override public void channelRead0(ChannelHandlerContext ctx, - LogEvent event) throws Exception { + LogEvent event) throws Exception { StringBuilder builder = new StringBuilder(); builder.append(event.getReceivedTimestamp()); builder.append(" ["); diff --git a/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java b/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java index 8812cc5b..76ea2b5b 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java @@ -20,18 +20,18 @@ public LogEventMonitor(InetSocketAddress address) { group = new NioEventLoopGroup(); bootstrap = new Bootstrap(); bootstrap.group(group) - .channel(NioDatagramChannel.class) - .option(ChannelOption.SO_BROADCAST, true) - .handler( new ChannelInitializer() { - @Override - protected void initChannel(Channel channel) - throws Exception { - ChannelPipeline pipeline = channel.pipeline(); - pipeline.addLast(new LogEventDecoder()); - pipeline.addLast(new LogEventHandler()); - } - } ) - .localAddress(address); + .channel(NioDatagramChannel.class) + .option(ChannelOption.SO_BROADCAST, true) + .handler( new ChannelInitializer() { + @Override + protected void initChannel(Channel channel) + throws Exception { + ChannelPipeline pipeline = channel.pipeline(); + pipeline.addLast(new LogEventDecoder()); + pipeline.addLast(new LogEventHandler()); + } + } ) + .localAddress(address); } public Channel bind() { @@ -45,10 +45,10 @@ public void stop() { public static void main(String[] args) throws Exception { if (args.length != 1) { throw new IllegalArgumentException( - "Usage: LogEventMonitor "); + "Usage: LogEventMonitor "); } LogEventMonitor monitor = new LogEventMonitor( - new InetSocketAddress(Integer.parseInt(args[0]))); + new InetSocketAddress(Integer.parseInt(args[0]))); try { Channel channel = monitor.bind(); System.out.println("LogEventMonitor running"); diff --git a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java index a20b66b8..82eaae92 100644 --- a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java +++ b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java @@ -17,7 +17,6 @@ */ public class EchoClient { private final String host; - private final int port; public EchoClient(String host, int port) { @@ -25,20 +24,6 @@ public EchoClient(String host, int port) { this.port = port; } - public static void main(String[] args) - throws Exception { - if (args.length != 2) { - System.err.println("Usage: " + EchoClient.class.getSimpleName() + - " " - ); - return; - } - - final String host = args[0]; - final int port = Integer.parseInt(args[1]); - new EchoClient(host, port).start(); - } - public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); @@ -52,15 +37,28 @@ public void start() public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( - new EchoClientHandler()); + new EchoClientHandler()); } }); - ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); } } + + public static void main(String[] args) + throws Exception { + if (args.length != 2) { + System.err.println("Usage: " + EchoClient.class.getSimpleName() + + " " + ); + return; + } + + final String host = args[0]; + final int port = Integer.parseInt(args[1]); + new EchoClient(host, port).start(); + } } diff --git a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java index f4ce1ed7..687a431a 100644 --- a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java +++ b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java @@ -15,32 +15,21 @@ @Sharable public class EchoClientHandler extends SimpleChannelInboundHandler { - /** - * @param ctx - */ @Override public void channelActive(ChannelHandlerContext ctx) { ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); } - /** - * @param ctx - * @param in - */ @Override public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) { System.out.println( "Client received: " + in.toString(CharsetUtil.UTF_8)); } - /** - * @param ctx - * @param cause - */ @Override public void exceptionCaught(ChannelHandlerContext ctx, - Throwable cause) { + Throwable cause) { cause.printStackTrace(); ctx.close(); } diff --git a/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java b/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java index b7a68cd0..b528e957 100644 --- a/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java +++ b/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java @@ -32,7 +32,7 @@ public void channelReadComplete(ChannelHandlerContext ctx) @Override public void exceptionCaught(ChannelHandlerContext ctx, - Throwable cause) { + Throwable cause) { cause.printStackTrace(); ctx.close(); } diff --git a/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java b/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java index 74fa9099..13080509 100644 --- a/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java +++ b/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java @@ -5,6 +5,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; +import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.util.CharsetUtil; import java.util.concurrent.Executor; @@ -12,16 +13,18 @@ /** * Listing 4.5 Writing to a Channel + * * Listing 4.6 Using a Channel from many threads * * @author Norman Maurer */ public class ChannelOperationExamples { + private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); /** * Listing 4.5 Writing to a Channel */ public static void writingToChannel() { - Channel channel = null; // Get the channel reference from somewhere + Channel channel = CHANNEL_FROM_SOMEWHERE; // Get the channel reference from somewhere ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8); ChannelFuture cf = channel.writeAndFlush(buf); cf.addListener(new ChannelFutureListener() { @@ -41,7 +44,7 @@ public void operationComplete(ChannelFuture future) { * Listing 4.6 Using a Channel from many threads */ public static void writingToChannelFromManyThreads() { - final Channel channel = null; // Get the channel reference from somewhere + final Channel channel = CHANNEL_FROM_SOMEWHERE; // Get the channel reference from somewhere final ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8); Runnable writer = new Runnable() { @@ -57,5 +60,6 @@ public void run() { // write in another thread executor.execute(writer); + //... } } diff --git a/chapter4/src/main/java/nia/chapter4/NettyNioServer.java b/chapter4/src/main/java/nia/chapter4/NettyNioServer.java index cce4f389..19ff7458 100644 --- a/chapter4/src/main/java/nia/chapter4/NettyNioServer.java +++ b/chapter4/src/main/java/nia/chapter4/NettyNioServer.java @@ -17,8 +17,7 @@ * @author Norman Maurer */ public class NettyNioServer { - public void server(int port) - throws Exception { + public void server(int port) throws Exception { final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"))); @@ -37,7 +36,8 @@ public void initChannel(SocketChannel ch) public void channelActive( ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(buf.duplicate()) - .addListener(ChannelFutureListener.CLOSE); + .addListener( + ChannelFutureListener.CLOSE); } }); } diff --git a/chapter4/src/main/java/nia/chapter4/NettyOioServer.java b/chapter4/src/main/java/nia/chapter4/NettyOioServer.java index d801cfb4..b82b4a0a 100644 --- a/chapter4/src/main/java/nia/chapter4/NettyOioServer.java +++ b/chapter4/src/main/java/nia/chapter4/NettyOioServer.java @@ -20,8 +20,7 @@ public class NettyOioServer { public void server(int port) throws Exception { final ByteBuf buf = - Unpooled.unreleasableBuffer(Unpooled.copiedBuffer( - "Hi!\r\n", Charset.forName("UTF-8"))); + Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"))); EventLoopGroup group = new OioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); diff --git a/chapter4/src/main/java/nia/chapter4/PlainNioServer.java b/chapter4/src/main/java/nia/chapter4/PlainNioServer.java index 200453a3..54fce8cc 100644 --- a/chapter4/src/main/java/nia/chapter4/PlainNioServer.java +++ b/chapter4/src/main/java/nia/chapter4/PlainNioServer.java @@ -34,7 +34,6 @@ public void serve(int port) throws IOException { //handle exception break; } - Set readyKeys = selector.selectedKeys(); Iterator iterator = readyKeys.iterator(); while (iterator.hasNext()) { diff --git a/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java b/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java index 95424b8e..143aab4f 100644 --- a/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java +++ b/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java @@ -1,9 +1,6 @@ package nia.chapter5; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.CompositeByteBuf; -import io.netty.buffer.Unpooled; +import io.netty.buffer.*; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.socket.nio.NioSocketChannel; @@ -34,7 +31,7 @@ * * Listing 5.8 Write data * - * Listing 5.9 Using ByteProcessor to find \r + * Listing 5.9 Using ByteBufProcessor to find \r * * Listing 5.10 Slice a ByteBuf * @@ -86,7 +83,7 @@ public static void directBuffer() { */ public static void byteBufferComposite(ByteBuffer header, ByteBuffer body) { // Use an array to hold the message parts - ByteBuffer[] message = { header, body }; + ByteBuffer[] message = new ByteBuffer[]{ header, body }; // Create a new ByteBuffer and use copy to merge the header and body ByteBuffer message2 = @@ -102,7 +99,6 @@ public static void byteBufferComposite(ByteBuffer header, ByteBuffer body) { */ public static void byteBufComposite() { CompositeByteBuf messageBuf = Unpooled.compositeBuffer(); - ByteBuf headerBuf = BYTE_BUF_FROM_SOMEWHERE; // can be backing or direct ByteBuf bodyBuf = BYTE_BUF_FROM_SOMEWHERE; // can be backing or direct messageBuf.addComponents(headerBuf, bodyBuf); @@ -128,7 +124,7 @@ public static void byteBufCompositeArray() { * Listing 5.6 Access data */ public static void byteBufRelativeAccess() { - ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; + ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere for (int i = 0; i < buffer.capacity(); i++) { byte b = buffer.getByte(i); System.out.println((char) b); @@ -139,7 +135,7 @@ public static void byteBufRelativeAccess() { * Listing 5.7 Read all data */ public static void readAllData() { - ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; + ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere while (buffer.isReadable()) { System.out.println(buffer.readByte()); } @@ -150,7 +146,7 @@ public static void readAllData() { */ public static void write() { // Fills the writable bytes of a buffer with random integers. - ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; + ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere while (buffer.writableBytes() >= 4) { buffer.writeInt(random.nextInt()); } @@ -162,10 +158,20 @@ public static void write() { * use {@link io.netty.buffer.ByteBufProcessor in Netty 4.0.x} */ public static void byteProcessor() { - ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; + ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere int index = buffer.forEachByte(ByteProcessor.FIND_CR); } + /** + * Listing 5.9 Using ByteBufProcessor to find \r + * + * use {@link io.netty.util.ByteProcessor in Netty 4.1.x} + */ + public static void byteBufProcessor() { + ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere + int index = buffer.forEachByte(ByteBufProcessor.FIND_CR); + } + /** * Listing 5.10 Slice a ByteBuf */ diff --git a/chapter5/src/main/java/nia.chapter5/package-info.java b/chapter5/src/main/java/nia.chapter5/package-info.java index 431894bd..f60420b3 100644 --- a/chapter5/src/main/java/nia.chapter5/package-info.java +++ b/chapter5/src/main/java/nia.chapter5/package-info.java @@ -17,7 +17,7 @@ * * Listing 5.8 Write data {@link nia.chapter5.ByteBufExamples#write()} * - * Listing 5.9 Using ByteProcessor to find \r {@link nia.chapter5.ByteBufExamples#byteProcessor()} + * Listing 5.9 Using ByteBufProcessor to find \r {@link nia.chapter5.ByteBufExamples#byteBufProcessor()} * * Listing 5.10 Slice a ByteBuf {@link nia.chapter5.ByteBufExamples#byteBufSlice()} * diff --git a/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java b/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java index 2a9da75f..e9ddf56a 100644 --- a/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java +++ b/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java @@ -13,6 +13,9 @@ public class ModifyChannelPipeline { private static final ChannelPipeline CHANNEL_PIPELINE_FROM_SOMEWHERE = DUMMY_INSTANCE; + /** + * Listing 6.5 Modify the ChannelPipeline + * */ public static void modifyPipeline() { ChannelPipeline pipeline = CHANNEL_PIPELINE_FROM_SOMEWHERE; // get reference to pipeline; FirstHandler firstHandler = new FirstHandler(); diff --git a/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java b/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java index fdcb2ac5..0afa8191 100644 --- a/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java +++ b/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java @@ -7,7 +7,6 @@ * * @author Norman Maurer */ - public class OutboundExceptionHandler extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, diff --git a/chapter6/src/main/java/nia/chapter6/WriteHandler.java b/chapter6/src/main/java/nia/chapter6/WriteHandler.java index f1120348..f853b16b 100644 --- a/chapter6/src/main/java/nia/chapter6/WriteHandler.java +++ b/chapter6/src/main/java/nia/chapter6/WriteHandler.java @@ -11,12 +11,10 @@ */ public class WriteHandler extends ChannelHandlerAdapter { private ChannelHandlerContext ctx; - @Override public void handlerAdded(ChannelHandlerContext ctx) { this.ctx = ctx; } - public void send(String msg) { ctx.writeAndFlush(msg); } diff --git a/chapter6/src/main/java/nia/chapter6/WriteHandlers.java b/chapter6/src/main/java/nia/chapter6/WriteHandlers.java index 9ae7263c..24296a5d 100644 --- a/chapter6/src/main/java/nia/chapter6/WriteHandlers.java +++ b/chapter6/src/main/java/nia/chapter6/WriteHandlers.java @@ -38,7 +38,7 @@ public static void writeViaChannel() { * */ public static void writeViaChannelPipeline() { ChannelHandlerContext ctx = CHANNEL_HANDLER_CONTEXT_FROM_SOMEWHERE; //get reference form somewhere - ChannelPipeline pipeline = CHANNEL_PIPELINE_FROM_SOMEWHERE; //get reference form somewhere + ChannelPipeline pipeline = ctx.pipeline(); //get reference form somewhere pipeline.write(Unpooled.copiedBuffer("Netty in Action", CharsetUtil.UTF_8)); diff --git a/chapter6/src/main/java/nia/chapter6/package-info.java b/chapter6/src/main/java/nia/chapter6/package-info.java index a9a0fac7..9fc4ea8b 100644 --- a/chapter6/src/main/java/nia/chapter6/package-info.java +++ b/chapter6/src/main/java/nia/chapter6/package-info.java @@ -9,7 +9,7 @@ * * Listing 6.4 Discarding and releasing outbound data {@link nia.chapter6.DiscardOutboundHandler} * - * Listing 6.5 Modify the ChannelPipeline {@link nia.chapter6.ModifyChannelPipeline} + * Listing 6.5 Modify the ChannelPipeline {@link nia.chapter6.ModifyChannelPipeline#modifyPipeline()} * * Listing 6.6 Accessing the Channel from a ChannelHandlerContext {@link nia.chapter6.WriteHandlers#writeViaChannel()} * diff --git a/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java b/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java index 384ced06..df172b0d 100644 --- a/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java +++ b/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java @@ -1,8 +1,5 @@ package nia.chapter7; -import io.netty.channel.Channel; -import io.netty.channel.socket.nio.NioSocketChannel; - import java.util.Collections; import java.util.List; @@ -12,8 +9,6 @@ * @author Norman Maurer */ public class EventLoopExamples { - private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); - /** * Listing 7.1 Executing tasks in an event loop * */ diff --git a/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java b/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java index f2a28a2f..84147ec0 100644 --- a/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java +++ b/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java @@ -29,15 +29,13 @@ public static void schedule() { ScheduledExecutorService executor = Executors.newScheduledThreadPool(10); - ScheduledFuture future = - executor.schedule( - new Runnable() { - @Override - public void run() { - System.out.println("Now it is 60 seconds later"); - } - }, 60, TimeUnit.SECONDS - ); + ScheduledFuture future = executor.schedule( + new Runnable() { + @Override + public void run() { + System.out.println("Now it is 60 seconds later"); + } + }, 60, TimeUnit.SECONDS); //... executor.shutdown(); } @@ -48,12 +46,12 @@ public void run() { public static void scheduleViaEventLoop() { Channel ch = CHANNEL_FROM_SOMEWHERE; // get reference from somewhere ScheduledFuture future = ch.eventLoop().schedule( - new Runnable() { - @Override - public void run() { - System.out.println("60 seconds later"); - } - }, 60, TimeUnit.SECONDS); + new Runnable() { + @Override + public void run() { + System.out.println("60 seconds later"); + } + }, 60, TimeUnit.SECONDS); } /** @@ -62,12 +60,12 @@ public void run() { public static void scheduleFixedViaEventLoop() { Channel ch = CHANNEL_FROM_SOMEWHERE; // get reference from somewhere ScheduledFuture future = ch.eventLoop().scheduleAtFixedRate( - new Runnable() { - @Override - public void run() { - System.out.println("Run every 60 seconds"); - } - }, 60, 60, TimeUnit.SECONDS); + new Runnable() { + @Override + public void run() { + System.out.println("Run every 60 seconds"); + } + }, 60, 60, TimeUnit.SECONDS); } /** diff --git a/chapter7/src/main/java/nia/chapter7/package-info.java b/chapter7/src/main/java/nia/chapter7/package-info.java index 4461f3dd..5bbc4798 100644 --- a/chapter7/src/main/java/nia/chapter7/package-info.java +++ b/chapter7/src/main/java/nia/chapter7/package-info.java @@ -1,7 +1,7 @@ /** * Created by kerr. * - * Listing 7.1 Executing tasks in an event loop {@link nia.chapter7.EventLoopExamples#blockUntilEventsReady()} + * Listing 7.1 Executing tasks in an event loop {@link nia.chapter7.EventLoopExamples#executeTaskInEventLoop()} * * Listing 7.2 Scheduling a task with a ScheduledExecutorService {@link nia.chapter7.ScheduleExamples#schedule()} * diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapClient.java b/chapter8/src/main/java/nia/chapter8/BootstrapClient.java index 9a24e8e3..223a15a4 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapClient.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapClient.java @@ -28,16 +28,14 @@ public void bootstrap() { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) - .handler( - new SimpleChannelInboundHandler() { - @Override - protected void channelRead0( - ChannelHandlerContext channelHandlerContext, - ByteBuf byteBuf) throws Exception { - System.out.println("Received data"); - } + .handler(new SimpleChannelInboundHandler() { + @Override + protected void channelRead0( + ChannelHandlerContext channelHandlerContext, + ByteBuf byteBuf) throws Exception { + System.out.println("Received data"); } - ); + }); ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java b/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java index 61ac7eb2..89acc2f2 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java @@ -25,26 +25,26 @@ public class BootstrapDatagramChannel { public void bootstrap() { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(new OioEventLoopGroup()).channel( - OioDatagramChannel.class).handler( - new SimpleChannelInboundHandler() { - @Override - public void channelRead0(ChannelHandlerContext ctx, - DatagramPacket msg) throws Exception { - // Do something with the packet - } + OioDatagramChannel.class).handler( + new SimpleChannelInboundHandler() { + @Override + public void channelRead0(ChannelHandlerContext ctx, + DatagramPacket msg) throws Exception { + // Do something with the packet } + } ); ChannelFuture future = bootstrap.bind(new InetSocketAddress(0)); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) - throws Exception { - if (channelFuture.isSuccess()) { - System.out.println("Channel bound"); - } else { - System.err.println("Bind attempt failed"); - channelFuture.cause().printStackTrace(); - } + throws Exception { + if (channelFuture.isSuccess()) { + System.out.println("Channel bound"); + } else { + System.err.println("Bind attempt failed"); + channelFuture.cause().printStackTrace(); + } } }); } diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapServer.java b/chapter8/src/main/java/nia/chapter8/BootstrapServer.java index 458b544b..d88b20ad 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapServer.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapServer.java @@ -30,9 +30,8 @@ public void bootstrap() { .childHandler(new SimpleChannelInboundHandler() { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, - ByteBuf byteBuf) throws Exception { + ByteBuf byteBuf) throws Exception { System.out.println("Received data"); - byteBuf.clear(); } }); ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); diff --git a/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java b/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java index cf78eb4c..aa4d7d63 100644 --- a/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java +++ b/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java @@ -28,9 +28,9 @@ public void bootstrap() { EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) - .channel(NioSocketChannel.class) + .channel(NioSocketChannel.class) //... - .handler( + .handler( new SimpleChannelInboundHandler() { @Override protected void channelRead0( @@ -39,7 +39,7 @@ protected void channelRead0( System.out.println("Received data"); } } - ); + ); bootstrap.connect(new InetSocketAddress("www.manning.com", 80)).syncUninterruptibly(); //,,, Future future = group.shutdownGracefully(); diff --git a/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java b/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java index 3aa27178..e2273a1c 100644 --- a/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java +++ b/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java @@ -31,14 +31,13 @@ public void bootstrap() { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(OioSocketChannel.class) .handler(new SimpleChannelInboundHandler() { - @Override - protected void channelRead0( - ChannelHandlerContext channelHandlerContext, - ByteBuf byteBuf) throws Exception { - System.out.println("Received data"); - } - } - ); + @Override + protected void channelRead0( + ChannelHandlerContext channelHandlerContext, + ByteBuf byteBuf) throws Exception { + System.out.println("Received data"); + } + }); ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); future.syncUninterruptibly(); diff --git a/chapter8/src/main/java/nia/chapter8/package-info.java b/chapter8/src/main/java/nia/chapter8/package-info.java index acca1cb4..5268dc34 100644 --- a/chapter8/src/main/java/nia/chapter8/package-info.java +++ b/chapter8/src/main/java/nia/chapter8/package-info.java @@ -7,7 +7,7 @@ * * Listing 8.4 Bootstrapping a server{@link nia.chapter8.BootstrapServer#bootstrap()} * - * Listing 8.5 Bootstrapping a server {@link nia.chapter8.BootstrapSharingEventLoopGroup} + * Listing 8.5 Bootstrapping a server {@link nia.chapter8.BootstrapSharingEventLoopGroup#bootstrap()} * * Listing 8.6 Bootstrapping and using ChannelInitializer {@link nia.chapter8.BootstrapWithInitializer#bootstrap()} * diff --git a/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java b/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java index 0fdae6cf..e18d8e7f 100644 --- a/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java +++ b/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java @@ -11,12 +11,11 @@ * * @author Norman Maurer */ -public class AbsIntegerEncoder - extends MessageToMessageEncoder { +public class AbsIntegerEncoder extends + MessageToMessageEncoder { @Override protected void encode(ChannelHandlerContext channelHandlerContext, - ByteBuf in, List out) - throws Exception { + ByteBuf in, List out) throws Exception { while (in.readableBytes() >= 4) { int value = Math.abs(in.readInt()); out.add(value); diff --git a/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java b/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java index 431675c7..afb883b3 100644 --- a/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java +++ b/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java @@ -5,6 +5,7 @@ import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.TooLongFrameException; import nia.chapter9.FrameChunkDecoder; +import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.*; @@ -30,7 +31,7 @@ public void testFramesDecoded() { assertTrue(channel.writeInbound(input.readBytes(2))); try { channel.writeInbound(input.readBytes(4)); - fail(); + Assert.fail(); } catch (TooLongFrameException e) { // expected exception } From 5630a53148cbf6f1f3bf07ed723311d3f9904c7e Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Fri, 21 Apr 2017 20:08:08 +0800 Subject: [PATCH 02/75] =?UTF-8?q?+=20=E6=B7=BB=E5=8A=A0=E7=AC=AC1=E7=AB=A0?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nia/chapter1/BlockingIoExample.java | 11 +++++++++-- .../main/java/nia/chapter1/ConnectExample.java | 15 ++++++++++----- .../main/java/nia/chapter1/ConnectHandler.java | 3 ++- .../src/main/java/nia/chapter1/package-info.java | 8 ++++---- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java index 94cf0bc1..abcde269 100644 --- a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java +++ b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java @@ -10,28 +10,35 @@ /** * Created by kerr. * - * Listing 1.1 Blocking I/O example + * 代码清单 1-1 阻塞 I/O 示例 */ public class BlockingIoExample { /** - * Listing 1.1 Blocking I/O example + * 代码清单 1-1 阻塞 I/O 示例 * */ public void serve(int portNumber) throws IOException { + //创建一个新的 ServerSocket,用以监听指定端口上的连接请求 ServerSocket serverSocket = new ServerSocket(portNumber); + //对accept()方法的调用将被阻塞,直到一个连接建立 Socket clientSocket = serverSocket.accept(); + //这些流对象都派生于该套接字的流对象 BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); String request, response; + //处理循环开始 while ((request = in.readLine()) != null) { if ("Done".equals(request)) { break; } } + //请求被传递给服务器的处理方法 response = processRequest(request); + //服务器的响应被发送给了客户端 out.println(response); + //继续执行处理循环 } private String processRequest(String request){ diff --git a/chapter1/src/main/java/nia/chapter1/ConnectExample.java b/chapter1/src/main/java/nia/chapter1/ConnectExample.java index fa3ab7cf..9108c7c3 100644 --- a/chapter1/src/main/java/nia/chapter1/ConnectExample.java +++ b/chapter1/src/main/java/nia/chapter1/ConnectExample.java @@ -13,38 +13,43 @@ /** * Created by kerr. * - * Listing 1.3 Asynchronous connect + * 代码清单 1-3 异步地建立连接 * - * Listing 1.4 Callback in action + * 代码清单 1-4 回调实战 */ public class ConnectExample { private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); /** - * Listing 1.3 Asynchronous connect + * 代码清单 1-3 异步地建立连接 * - * Listing 1.4 Callback in action + * 代码清单 1-4 回调实战 * */ public static void connect() { Channel channel = CHANNEL_FROM_SOMEWHERE; //reference form somewhere // Does not block + //异步地连接到远程节点 ChannelFuture future = channel.connect( new InetSocketAddress("192.168.0.1", 25)); + //注册一个 ChannelFutureListener,以便在操作完成时获得通知 future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) { + //检查操作的状态 if (future.isSuccess()) { + //如果操作是成功的,则创建一个 ByteBuf 以持有数据 ByteBuf buffer = Unpooled.copiedBuffer( "Hello", Charset.defaultCharset()); + //将数据异步地发送到远程节点。返回一个 ChannelFuture ChannelFuture wf = future.channel() .writeAndFlush(buffer); // ... } else { + //如果发生错误,则访问描述原因的 Throwable Throwable cause = future.cause(); cause.printStackTrace(); } } }); - } } \ No newline at end of file diff --git a/chapter1/src/main/java/nia/chapter1/ConnectHandler.java b/chapter1/src/main/java/nia/chapter1/ConnectHandler.java index 01313d78..2e04d547 100644 --- a/chapter1/src/main/java/nia/chapter1/ConnectHandler.java +++ b/chapter1/src/main/java/nia/chapter1/ConnectHandler.java @@ -6,10 +6,11 @@ /** * Created by kerr. * - * Listing 1.2 ChannelHandler triggered by a callback + * 代码清单 1-2 被回调触发的 ChannelHandler */ public class ConnectHandler extends ChannelInboundHandlerAdapter { @Override + //当一个新的连接已经被建立时,channelActive(ChannelHandlerContext)将会被调用 public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println( diff --git a/chapter1/src/main/java/nia/chapter1/package-info.java b/chapter1/src/main/java/nia/chapter1/package-info.java index 8b659ac8..66a62fd1 100644 --- a/chapter1/src/main/java/nia/chapter1/package-info.java +++ b/chapter1/src/main/java/nia/chapter1/package-info.java @@ -1,12 +1,12 @@ /** * kerr. * - * Listing 1.1 Blocking I/O example {@link nia.chapter1.BlockingIoExample#serve(int)} + * 代码清单 1-1 阻塞 I/O 示例 {@link nia.chapter1.BlockingIoExample#serve(int)} * - * Listing 1.2 ChannelHandler triggered by a callback {@link nia.chapter1.ConnectHandler} + * 代码清单 1-2 被回调触发的 ChannelHandler {@link nia.chapter1.ConnectHandler} * - * Listing 1.3 Asynchronous connect {@link nia.chapter1.ConnectExample#connect()} + * 代码清单 1-3 异步地建立连接 {@link nia.chapter1.ConnectExample#connect()} * - * Listing 1.4 Callback in action {@link nia.chapter1.ConnectExample#connect()} + * 代码清单 1-4 回调实战 {@link nia.chapter1.ConnectExample#connect()} */ package nia.chapter1; \ No newline at end of file From 840ea3a80eb45f8f33714a2aa5d6ac7d6c2d88f7 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Fri, 21 Apr 2017 20:47:06 +0800 Subject: [PATCH 03/75] =?UTF-8?q?+=20=E6=B7=BB=E5=8A=A0=E7=AC=AC2=E7=AB=A0?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nia/chapter2/echoclient/EchoClient.java | 10 +++++++++- .../chapter2/echoclient/EchoClientHandler.java | 6 +++++- .../src/main/java/nia/chapter2/package-info.java | 4 ++-- .../java/nia/chapter2/echoserver/EchoServer.java | 16 ++++++++++++++-- .../chapter2/echoserver/EchoServerHandler.java | 8 +++++++- .../src/main/java/nia/chapter2/package-info.java | 4 ++-- 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java index 82eaae92..87408844 100644 --- a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java +++ b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClient.java @@ -11,7 +11,7 @@ import java.net.InetSocketAddress; /** - * Listing 2.4 Main class for the client + * 代码清单 2-4 客户端的主类 * * @author Norman Maurer */ @@ -28,10 +28,15 @@ public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { + //创建 Bootstrap Bootstrap b = new Bootstrap(); + //指定 EventLoopGroup 以处理客户端事件;需要适用于 NIO 的实现 b.group(group) + //适用于 NIO 传输的Channel 类型 .channel(NioSocketChannel.class) + //设置服务器的InetSocketAddress .remoteAddress(new InetSocketAddress(host, port)) + //在创建Channel时,向 ChannelPipeline中添加一个 EchoClientHandler实例 .handler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) @@ -40,9 +45,12 @@ public void initChannel(SocketChannel ch) new EchoClientHandler()); } }); + //连接到远程节点,阻塞等待直到连接完成 ChannelFuture f = b.connect().sync(); + //阻塞,直到Channel 关闭 f.channel().closeFuture().sync(); } finally { + //关闭线程池并且释放所有的资源 group.shutdownGracefully().sync(); } } diff --git a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java index 687a431a..a3fb2b66 100644 --- a/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java +++ b/chapter2/Client/src/main/java/nia/chapter2/echoclient/EchoClientHandler.java @@ -8,26 +8,30 @@ import io.netty.util.CharsetUtil; /** - * Listing 2.3 ChannelHandler for the client + * 代码清单 2-3 客户端的 ChannelHandler * * @author Norman Maurer */ @Sharable +//标记该类的实例可以被多个 Channel 共享 public class EchoClientHandler extends SimpleChannelInboundHandler { @Override public void channelActive(ChannelHandlerContext ctx) { + //当被通知 Channel是活跃的时候,发送一条消息 ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); } @Override public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) { + //记录已接收消息的转储 System.out.println( "Client received: " + in.toString(CharsetUtil.UTF_8)); } @Override + //在发生异常时,记录错误并关闭Channel public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); diff --git a/chapter2/Client/src/main/java/nia/chapter2/package-info.java b/chapter2/Client/src/main/java/nia/chapter2/package-info.java index 6138c69e..a0606b1f 100644 --- a/chapter2/Client/src/main/java/nia/chapter2/package-info.java +++ b/chapter2/Client/src/main/java/nia/chapter2/package-info.java @@ -1,8 +1,8 @@ /** * Created by kerr. * - * Listing 2.3 ChannelHandler for the client {@link nia.chapter2.echoclient.EchoClientHandler} + * 代码清单 2-3 客户端的 ChannelHandler {@link nia.chapter2.echoclient.EchoClientHandler} * - * Listing 2.4 Main class for the client {@link nia.chapter2.echoclient.EchoClient} + * 代码清单 2-4 客户端的主类 {@link nia.chapter2.echoclient.EchoClient} */ package nia.chapter2; \ No newline at end of file diff --git a/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServer.java b/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServer.java index 398c6bcb..4e3c5fa9 100644 --- a/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServer.java +++ b/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServer.java @@ -11,7 +11,7 @@ import java.net.InetSocketAddress; /** - * Listing 2.2 EchoServer class + * 代码清单 2-2 EchoServer 类 * * @author Norman Maurer */ @@ -30,30 +30,42 @@ public static void main(String[] args) ); return; } + //设置端口值(如果端口参数的格式不正确,则抛出一个NumberFormatException) int port = Integer.parseInt(args[0]); + //调用服务器的 start()方法 new EchoServer(port).start(); } public void start() throws Exception { final EchoServerHandler serverHandler = new EchoServerHandler(); + //(1) 创建EventLoopGroup EventLoopGroup group = new NioEventLoopGroup(); try { + //(2) 创建ServerBootstrap ServerBootstrap b = new ServerBootstrap(); b.group(group) + //(3) 指定所使用的 NIO 传输 Channel .channel(NioServerSocketChannel.class) + //(4) 使用指定的端口设置套接字地址 .localAddress(new InetSocketAddress(port)) + //(5) 添加一个EchoServerHandler到于Channel的 ChannelPipeline .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { + //EchoServerHandler 被标注为@Shareable,所以我们可以总是使用同样的实例 + //这里对于所有的客户端连接来说,都会使用同一个 EchoServerHandler,因为其被标注为@Sharable, + //这将在后面的章节中讲到。 ch.pipeline().addLast(serverHandler); } }); - + //(6) 异步地绑定服务器;调用 sync()方法阻塞等待直到绑定完成 ChannelFuture f = b.bind().sync(); System.out.println(EchoServer.class.getName() + " started and listening for connections on " + f.channel().localAddress()); + //(7) 获取 Channel 的CloseFuture,并且阻塞当前线程直到它完成 f.channel().closeFuture().sync(); } finally { + //(8) 关闭 EventLoopGroup,释放所有的资源 group.shutdownGracefully().sync(); } } diff --git a/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java b/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java index b528e957..6848479c 100644 --- a/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java +++ b/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java @@ -9,23 +9,27 @@ import io.netty.util.CharsetUtil; /** - * Listing 2.1 EchoServerHandler + * 代码清单 2-1 EchoServerHandler * * @author Norman Maurer */ +//标示一个ChannelHandler可以被多个 Channel 安全地共享 @Sharable public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf in = (ByteBuf) msg; + //将消息记录到控制台 System.out.println( "Server received: " + in.toString(CharsetUtil.UTF_8)); + //将接收到的消息写给发送者,而不冲刷出站消息 ctx.write(in); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + //将未决消息冲刷到远程节点,并且关闭该 Channel ctx.writeAndFlush(Unpooled.EMPTY_BUFFER) .addListener(ChannelFutureListener.CLOSE); } @@ -33,7 +37,9 @@ public void channelReadComplete(ChannelHandlerContext ctx) @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + //打印异常栈跟踪 cause.printStackTrace(); + //关闭该Channel ctx.close(); } } diff --git a/chapter2/Server/src/main/java/nia/chapter2/package-info.java b/chapter2/Server/src/main/java/nia/chapter2/package-info.java index e07ee2b8..909d3eec 100644 --- a/chapter2/Server/src/main/java/nia/chapter2/package-info.java +++ b/chapter2/Server/src/main/java/nia/chapter2/package-info.java @@ -1,8 +1,8 @@ /** * Created by kerr. * - * Listing 2.1 EchoServerHandler {@link nia.chapter2.echoserver.EchoServerHandler} + * 代码清单 2-1 EchoServerHandler {@link nia.chapter2.echoserver.EchoServerHandler} * - * Listing 2.2 EchoServer class {@link nia.chapter2.echoserver.EchoServer} + * 代码清单 2-2 EchoServer 类 {@link nia.chapter2.echoserver.EchoServer} */ package nia.chapter2; \ No newline at end of file From bb0bfc8c488d678267d95148bbcad4fa1d60278e Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Fri, 21 Apr 2017 22:10:36 +0800 Subject: [PATCH 04/75] =?UTF-8?q?+=20=E6=B7=BB=E5=8A=A0=E7=AC=AC4=E7=AB=A0?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nia/chapter4/ChannelOperationExamples.java | 17 +++++++++++++---- .../main/java/nia/chapter4/NettyNioServer.java | 10 +++++++++- .../main/java/nia/chapter4/NettyOioServer.java | 8 ++++++++ .../main/java/nia/chapter4/PlainNioServer.java | 12 +++++++++++- .../main/java/nia/chapter4/PlainOioServer.java | 8 +++++++- .../main/java/nia/chapter4/package-info.java | 12 ++++++------ 6 files changed, 54 insertions(+), 13 deletions(-) diff --git a/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java b/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java index 13080509..a75eb180 100644 --- a/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java +++ b/chapter4/src/main/java/nia/chapter4/ChannelOperationExamples.java @@ -12,27 +12,31 @@ import java.util.concurrent.Executors; /** - * Listing 4.5 Writing to a Channel + * 代码清单 4-5 写出到 Channel * - * Listing 4.6 Using a Channel from many threads + * 代码清单 4-6 从多个线程使用同一个 Channel * * @author Norman Maurer */ public class ChannelOperationExamples { private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); /** - * Listing 4.5 Writing to a Channel + * 代码清单 4-5 写出到 Channel */ public static void writingToChannel() { Channel channel = CHANNEL_FROM_SOMEWHERE; // Get the channel reference from somewhere + //创建持有要写数据的 ByteBuf ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8); ChannelFuture cf = channel.writeAndFlush(buf); + //添加 ChannelFutureListener 以便在写操作完成后接收通知 cf.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) { + //写操作完成,并且没有错误发生 if (future.isSuccess()) { System.out.println("Write successful"); } else { + //记录错误 System.err.println("Write error"); future.cause().printStackTrace(); } @@ -41,23 +45,28 @@ public void operationComplete(ChannelFuture future) { } /** - * Listing 4.6 Using a Channel from many threads + * 代码清单 4-6 从多个线程使用同一个 Channel */ public static void writingToChannelFromManyThreads() { final Channel channel = CHANNEL_FROM_SOMEWHERE; // Get the channel reference from somewhere + //创建持有要写数据的ByteBuf final ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8); + //创建将数据写到Channel 的 Runnable Runnable writer = new Runnable() { @Override public void run() { channel.write(buf.duplicate()); } }; + //获取到线程池Executor 的引用 Executor executor = Executors.newCachedThreadPool(); + //递交写任务给线程池以便在某个线程中执行 // write in one thread executor.execute(writer); + //递交另一个写任务以便在另一个线程中执行 // write in another thread executor.execute(writer); //... diff --git a/chapter4/src/main/java/nia/chapter4/NettyNioServer.java b/chapter4/src/main/java/nia/chapter4/NettyNioServer.java index 19ff7458..e90503b3 100644 --- a/chapter4/src/main/java/nia/chapter4/NettyNioServer.java +++ b/chapter4/src/main/java/nia/chapter4/NettyNioServer.java @@ -12,7 +12,7 @@ import java.nio.charset.Charset; /** - * Listing 4.4 Asynchronous networking with Netty + * 代码清单 4-4 使用 Netty 的异步网络处理 * * @author Norman Maurer */ @@ -21,19 +21,25 @@ public void server(int port) throws Exception { final ByteBuf buf = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"))); + //为非阻塞模式使用NioEventLoopGroup NioEventLoopGroup group = new NioEventLoopGroup(); try { + //创建ServerBootstrap ServerBootstrap b = new ServerBootstrap(); b.group(group).channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) + //指定 ChannelInitializer,对于每个已接受的连接都调用它 .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( + //添加 ChannelInboundHandlerAdapter以接收和处理事件 new ChannelInboundHandlerAdapter() { @Override public void channelActive( + //将消息写到客户端,并添加ChannelFutureListener, + //以便消息一被写完就关闭连接 ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(buf.duplicate()) .addListener( @@ -43,9 +49,11 @@ public void channelActive( } } ); + //绑定服务器以接受连接 ChannelFuture f = b.bind().sync(); f.channel().closeFuture().sync(); } finally { + //释放所有的资源 group.shutdownGracefully().sync(); } } diff --git a/chapter4/src/main/java/nia/chapter4/NettyOioServer.java b/chapter4/src/main/java/nia/chapter4/NettyOioServer.java index b82b4a0a..b3b88fa5 100644 --- a/chapter4/src/main/java/nia/chapter4/NettyOioServer.java +++ b/chapter4/src/main/java/nia/chapter4/NettyOioServer.java @@ -23,15 +23,19 @@ public void server(int port) Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"))); EventLoopGroup group = new OioEventLoopGroup(); try { + //创建 ServerBootstrap ServerBootstrap b = new ServerBootstrap(); b.group(group) + //使用 OioEventLoopGroup以允许阻塞模式(旧的I/O) .channel(OioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) + //指定 ChannelInitializer,对于每个已接受的连接都调用它 .childHandler(new ChannelInitializer() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( + //添加一个 ChannelInboundHandlerAdapter以拦截和处理事件 new ChannelInboundHandlerAdapter() { @Override public void channelActive( @@ -39,14 +43,18 @@ public void channelActive( throws Exception { ctx.writeAndFlush(buf.duplicate()) .addListener( + //将消息写到客户端,并添加 ChannelFutureListener, + //以便消息一被写完就关闭连接 ChannelFutureListener.CLOSE); } }); } }); + //绑定服务器以接受连接 ChannelFuture f = b.bind().sync(); f.channel().closeFuture().sync(); } finally { + //释放所有的资源 group.shutdownGracefully().sync(); } } diff --git a/chapter4/src/main/java/nia/chapter4/PlainNioServer.java b/chapter4/src/main/java/nia/chapter4/PlainNioServer.java index 54fce8cc..1db9e38b 100644 --- a/chapter4/src/main/java/nia/chapter4/PlainNioServer.java +++ b/chapter4/src/main/java/nia/chapter4/PlainNioServer.java @@ -12,7 +12,7 @@ import java.util.Set; /** - * Listing 4.2 Asynchronous networking without Netty + * 代码清单 4-2 未使用 Netty 的异步网络编程 * * @author Norman Maurer */ @@ -22,44 +22,54 @@ public void serve(int port) throws IOException { serverChannel.configureBlocking(false); ServerSocket ss = serverChannel.socket(); InetSocketAddress address = new InetSocketAddress(port); + //将服务器绑定到选定的端口 ss.bind(address); + //打开Selector来处理 Channel Selector selector = Selector.open(); + //将ServerSocket注册到Selector以接受连接 serverChannel.register(selector, SelectionKey.OP_ACCEPT); final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes()); for (;;){ try { + //等待需要处理的新事件;阻塞将一直持续到下一个传入事件 selector.select(); } catch (IOException ex) { ex.printStackTrace(); //handle exception break; } + //获取所有接收事件的SelectionKey实例 Set readyKeys = selector.selectedKeys(); Iterator iterator = readyKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); try { + //检查事件是否是一个新的已经就绪可以被接受的连接 if (key.isAcceptable()) { ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel client = server.accept(); client.configureBlocking(false); + //接受客户端,并将它注册到选择器 client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate()); System.out.println( "Accepted connection from " + client); } + //检查套接字是否已经准备好写数据 if (key.isWritable()) { SocketChannel client = (SocketChannel) key.channel(); ByteBuffer buffer = (ByteBuffer) key.attachment(); while (buffer.hasRemaining()) { + //将数据写到已连接的客户端 if (client.write(buffer) == 0) { break; } } + //关闭连接 client.close(); } } catch (IOException ex) { diff --git a/chapter4/src/main/java/nia/chapter4/PlainOioServer.java b/chapter4/src/main/java/nia/chapter4/PlainOioServer.java index c91f3063..84232573 100644 --- a/chapter4/src/main/java/nia/chapter4/PlainOioServer.java +++ b/chapter4/src/main/java/nia/chapter4/PlainOioServer.java @@ -7,27 +7,32 @@ import java.nio.charset.Charset; /** - * Listing 4.1 Blocking networking without Netty + * 代码清单 4-1 未使用 Netty 的阻塞网络编程 * * @author Norman Maurer */ public class PlainOioServer { public void serve(int port) throws IOException { + //将服务器绑定到指定端口 final ServerSocket socket = new ServerSocket(port); try { for(;;) { + //接受连接 final Socket clientSocket = socket.accept(); System.out.println( "Accepted connection from " + clientSocket); + //创建一个新的线程来处理该连接 new Thread(new Runnable() { @Override public void run() { OutputStream out; try { + //将消息写给已连接的客户端 out = clientSocket.getOutputStream(); out.write("Hi!\r\n".getBytes( Charset.forName("UTF-8"))); out.flush(); + //关闭连接 clientSocket.close(); } catch (IOException e) { e.printStackTrace(); @@ -38,6 +43,7 @@ public void run() { // ignore on close } } + //启动线程 } }).start(); } diff --git a/chapter4/src/main/java/nia/chapter4/package-info.java b/chapter4/src/main/java/nia/chapter4/package-info.java index fa771ded..20d9a156 100644 --- a/chapter4/src/main/java/nia/chapter4/package-info.java +++ b/chapter4/src/main/java/nia/chapter4/package-info.java @@ -1,16 +1,16 @@ /** * Created by kerr. * - * Listing 4.1 Blocking networking without Netty {@link nia.chapter4.PlainOioServer} + * 代码清单 4-1 未使用 Netty 的阻塞网络编程 {@link nia.chapter4.PlainOioServer} * - * Listing 4.2 Asynchronous networking without Netty {@link nia.chapter4.PlainNioServer} + * 代码清单 4-2 未使用 Netty 的异步网络编程 {@link nia.chapter4.PlainNioServer} * - * Listing 4.3 Blocking networking with Netty {@link nia.chapter4.NettyOioServer} + * 代码清单 4-3 使用 Netty 的阻塞网络处理 {@link nia.chapter4.NettyOioServer} * - * Listing 4.4 Asynchronous networking with Netty {@link nia.chapter4.NettyNioServer} + * 代码清单 4-4 使用 Netty 的异步网络处理 {@link nia.chapter4.NettyNioServer} * - * Listing 4.5 Writing to a Channel {@link nia.chapter4.ChannelOperationExamples#writingToChannel()} + * 代码清单 4-5 写出到 Channel {@link nia.chapter4.ChannelOperationExamples#writingToChannel()} * - * Listing 4.6 Using a Channel from many threads {@link nia.chapter4.ChannelOperationExamples#writingToChannelFromManyThreads()} + * 代码清单 4-6 从多个线程使用同一个 Channel {@link nia.chapter4.ChannelOperationExamples#writingToChannelFromManyThreads()} */ package nia.chapter4; \ No newline at end of file From f2e4a2c1fce54e1c5ddf1ef2136974cdcea63979 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Fri, 21 Apr 2017 23:58:16 +0800 Subject: [PATCH 05/75] =?UTF-8?q?+=20=E6=B7=BB=E5=8A=A0=E7=AC=AC5=E7=AB=A0?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nia/chapter1/BlockingIoExample.java | 10 +- .../java/nia.chapter5/ByteBufExamples.java | 111 ++++++++++++------ .../main/java/nia.chapter5/package-info.java | 2 +- 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java index abcde269..bd2d002f 100644 --- a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java +++ b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java @@ -33,12 +33,12 @@ public void serve(int portNumber) throws IOException { if ("Done".equals(request)) { break; } + //请求被传递给服务器的处理方法 + response = processRequest(request); + //服务器的响应被发送给了客户端 + out.println(response); + //继续执行处理循环 } - //请求被传递给服务器的处理方法 - response = processRequest(request); - //服务器的响应被发送给了客户端 - out.println(response); - //继续执行处理循环 } private String processRequest(String request){ diff --git a/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java b/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java index 143aab4f..1b892bb9 100644 --- a/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java +++ b/chapter5/src/main/java/nia.chapter5/ByteBufExamples.java @@ -15,37 +15,37 @@ /** * Created by kerr. * - * Listing 5.1 Backing array + * 代码清单 5-1 支撑数组 * - * Listing 5.2 Direct buffer data access + * 代码清单 5-2 访问直接缓冲区的数据 * - * Listing 5.3 Composite buffer pattern using ByteBuffer + * 代码清单 5-3 使用 ByteBuffer 的复合缓冲区模式 * - * Listing 5.4 Composite buffer pattern using CompositeByteBuf + * 代码清单 5-4 使用 CompositeByteBuf 的复合缓冲区模式 * - * Listing 5.5 Accessing the data in a CompositeByteBuf + * 代码清单 5-5 访问 CompositeByteBuf 中的数据 * - * Listing 5.6 Access data + * 代码清单 5-6 访问数据 * - * Listing 5.7 Read all data + * 代码清单 5-7 读取所有数据 * - * Listing 5.8 Write data + * 代码清单 5-8 写数据 * - * Listing 5.9 Using ByteBufProcessor to find \r + * 代码清单 5-9 使用 ByteBufProcessor 来寻找\r * - * Listing 5.10 Slice a ByteBuf + * 代码清单 5-10 对 ByteBuf 进行切片 * - * Listing 5.11 Copying a ByteBuf + * 代码清单 5-11 复制一个 ByteBuf * - * Listing 5.12 get() and set() usage + * 代码清单 5-12 get()和 set()方法的用法 * - * Listing 5.13 read() and write() operations on the ByteBuf + * 代码清单 5-13 ByteBuf 上的 read()和 write()操作 * - * Listing 5.14 Obtaining a ByteBufAllocator reference + * 代码清单 5-14 获取一个到 ByteBufAllocator 的引用 * - * Listing 5.15 Reference counting + * 代码清单 5-15 引用计数 * - * Listing 5.16 Release reference-counted object + * 代码清单 5-16 释放引用计数的对象 */ public class ByteBufExamples { private final static Random random = new Random(); @@ -53,33 +53,43 @@ public class ByteBufExamples { private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); private static final ChannelHandlerContext CHANNEL_HANDLER_CONTEXT_FROM_SOMEWHERE = DUMMY_INSTANCE; /** - * Listing 5.1 Backing array + * 代码清单 5-1 支撑数组 */ public static void heapBuffer() { ByteBuf heapBuf = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere + //检查 ByteBuf 是否有一个支撑数组 if (heapBuf.hasArray()) { + //如果有,则获取对该数组的引用 byte[] array = heapBuf.array(); + //计算第一个字节的偏移量 int offset = heapBuf.arrayOffset() + heapBuf.readerIndex(); + //获得可读字节数 int length = heapBuf.readableBytes(); + //使用数组、偏移量和长度作为参数调用你的方法 handleArray(array, offset, length); } } /** - * Listing 5.2 Direct buffer data access + * 代码清单 5-2 访问直接缓冲区的数据 */ public static void directBuffer() { ByteBuf directBuf = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere + //检查 ByteBuf 是否由数组支撑。如果不是,则这是一个直接缓冲区 if (!directBuf.hasArray()) { + //获取可读字节数 int length = directBuf.readableBytes(); + //分配一个新的数组来保存具有该长度的字节数据 byte[] array = new byte[length]; + //将字节复制到该数组 directBuf.getBytes(directBuf.readerIndex(), array); + //使用数组、偏移量和长度作为参数调用你的方法 handleArray(array, 0, length); } } /** - * Listing 5.3 Composite buffer pattern using ByteBuffer + * 代码清单 5-3 使用 ByteBuffer 的复合缓冲区模式 */ public static void byteBufferComposite(ByteBuffer header, ByteBuffer body) { // Use an array to hold the message parts @@ -95,33 +105,40 @@ public static void byteBufferComposite(ByteBuffer header, ByteBuffer body) { /** - * Listing 5.4 Composite buffer pattern using CompositeByteBuf + * 代码清单 5-4 使用 CompositeByteBuf 的复合缓冲区模式 */ public static void byteBufComposite() { CompositeByteBuf messageBuf = Unpooled.compositeBuffer(); ByteBuf headerBuf = BYTE_BUF_FROM_SOMEWHERE; // can be backing or direct ByteBuf bodyBuf = BYTE_BUF_FROM_SOMEWHERE; // can be backing or direct + //将 ByteBuf 实例追加到 CompositeByteBuf messageBuf.addComponents(headerBuf, bodyBuf); //... + //删除位于索引位置为 0(第一个组件)的 ByteBuf messageBuf.removeComponent(0); // remove the header + //循环遍历所有的 ByteBuf 实例 for (ByteBuf buf : messageBuf) { System.out.println(buf.toString()); } } /** - * Listing 5.5 Accessing the data in a CompositeByteBuf + * 代码清单 5-5 访问 CompositeByteBuf 中的数据 */ public static void byteBufCompositeArray() { CompositeByteBuf compBuf = Unpooled.compositeBuffer(); + //获得可读字节数 int length = compBuf.readableBytes(); + //分配一个具有可读字节数长度的新数组 byte[] array = new byte[length]; + //将字节读到该数组中 compBuf.getBytes(compBuf.readerIndex(), array); + //使用偏移量和长度作为参数使用该数组 handleArray(array, 0, array.length); } /** - * Listing 5.6 Access data + * 代码清单 5-6 访问数据 */ public static void byteBufRelativeAccess() { ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere @@ -132,7 +149,7 @@ public static void byteBufRelativeAccess() { } /** - * Listing 5.7 Read all data + * 代码清单 5-7 读取所有数据 */ public static void readAllData() { ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere @@ -142,7 +159,7 @@ public static void readAllData() { } /** - * Listing 5.8 Write data + * 代码清单 5-8 写数据 */ public static void write() { // Fills the writable bytes of a buffer with random integers. @@ -153,7 +170,7 @@ public static void write() { } /** - * Listing 5.9 Using ByteProcessor to find \r + * 代码清单 5-9 使用 ByteBufProcessor 来寻找\r * * use {@link io.netty.buffer.ByteBufProcessor in Netty 4.0.x} */ @@ -163,7 +180,7 @@ public static void byteProcessor() { } /** - * Listing 5.9 Using ByteBufProcessor to find \r + * 代码清单 5-9 使用 ByteBufProcessor 来寻找\r * * use {@link io.netty.util.ByteProcessor in Netty 4.1.x} */ @@ -173,89 +190,117 @@ public static void byteBufProcessor() { } /** - * Listing 5.10 Slice a ByteBuf + * 代码清单 5-10 对 ByteBuf 进行切片 */ public static void byteBufSlice() { Charset utf8 = Charset.forName("UTF-8"); + //创建一个用于保存给定字符串的字节的 ByteBuf ByteBuf buf = Unpooled.copiedBuffer("Netty in Action rocks!", utf8); + //创建该 ByteBuf 从索引 0 开始到索引 15 结束的一个新切片 ByteBuf sliced = buf.slice(0, 15); + //将打印“Netty in Action” System.out.println(sliced.toString(utf8)); + //更新索引 0 处的字节 buf.setByte(0, (byte)'J'); + //将会成功,因为数据是共享的,对其中一个所做的更改对另外一个也是可见的 assert buf.getByte(0) == sliced.getByte(0); } /** - * Listing 5.11 Copying a ByteBuf + * 代码清单 5-11 复制一个 ByteBuf */ public static void byteBufCopy() { Charset utf8 = Charset.forName("UTF-8"); + //创建 ByteBuf 以保存所提供的字符串的字节 ByteBuf buf = Unpooled.copiedBuffer("Netty in Action rocks!", utf8); + //创建该 ByteBuf 从索引 0 开始到索引 15 结束的分段的副本 ByteBuf copy = buf.copy(0, 15); + //将打印“Netty in Action” System.out.println(copy.toString(utf8)); + //更新索引 0 处的字节 buf.setByte(0, (byte)'J'); + //将会成功,因为数据不是共享的 assert buf.getByte(0) != copy.getByte(0); } /** - * Listing 5.12 get() and set() usage + * 代码清单 5-12 get()和 set()方法的用法 */ public static void byteBufSetGet() { Charset utf8 = Charset.forName("UTF-8"); + //创建一个新的 ByteBuf以保存给定字符串的字节 ByteBuf buf = Unpooled.copiedBuffer("Netty in Action rocks!", utf8); + //打印第一个字符'N' System.out.println((char)buf.getByte(0)); + //存储当前的 readerIndex 和 writerIndex int readerIndex = buf.readerIndex(); int writerIndex = buf.writerIndex(); + //将索引 0 处的字 节更新为字符'B' buf.setByte(0, (byte)'B'); + //打印第一个字符,现在是'B' System.out.println((char)buf.getByte(0)); + //将会成功,因为这些操作并不会修改相应的索引 assert readerIndex == buf.readerIndex(); assert writerIndex == buf.writerIndex(); } /** - * Listing 5.13 read() and write() operations on the ByteBuf + * 代码清单 5-13 ByteBuf 上的 read()和 write()操作 */ public static void byteBufWriteRead() { Charset utf8 = Charset.forName("UTF-8"); + //创建一个新的 ByteBuf 以保存给定字符串的字节 ByteBuf buf = Unpooled.copiedBuffer("Netty in Action rocks!", utf8); + //打印第一个字符'N' System.out.println((char)buf.readByte()); + //存储当前的readerIndex int readerIndex = buf.readerIndex(); + //存储当前的writerIndex int writerIndex = buf.writerIndex(); + //将字符 '?'追加到缓冲区 buf.writeByte((byte)'?'); assert readerIndex == buf.readerIndex(); + //将会成功,因为 writeByte()方法移动了 writerIndex assert writerIndex != buf.writerIndex(); } private static void handleArray(byte[] array, int offset, int len) {} /** - * Listing 5.14 Obtaining a ByteBufAllocator reference + * 代码清单 5-14 获取一个到 ByteBufAllocator 的引用 */ public static void obtainingByteBufAllocatorReference(){ Channel channel = CHANNEL_FROM_SOMEWHERE; //get reference form somewhere + //从 Channel 获取一个到ByteBufAllocator 的引用 ByteBufAllocator allocator = channel.alloc(); //... ChannelHandlerContext ctx = CHANNEL_HANDLER_CONTEXT_FROM_SOMEWHERE; //get reference form somewhere + //从 ChannelHandlerContext 获取一个到 ByteBufAllocator 的引用 ByteBufAllocator allocator2 = ctx.alloc(); //... } /** - * Listing 5.15 Reference counting + * 代码清单 5-15 引用计数 * */ public static void referenceCounting(){ Channel channel = CHANNEL_FROM_SOMEWHERE; //get reference form somewhere + //从 Channel 获取ByteBufAllocator ByteBufAllocator allocator = channel.alloc(); //... + //从 ByteBufAllocator分配一个 ByteBuf ByteBuf buffer = allocator.directBuffer(); + //检查引用计数是否为预期的 1 assert buffer.refCnt() == 1; //... } /** - * Listing 5.16 Release reference-counted object + * 代码清单 5-16 释放引用计数的对象 */ public static void releaseReferenceCountedObject(){ ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhere + //减少到该对象的活动引用。当减少到 0 时,该对象被释放,并且该方法返回 true boolean released = buffer.release(); //... } diff --git a/chapter5/src/main/java/nia.chapter5/package-info.java b/chapter5/src/main/java/nia.chapter5/package-info.java index f60420b3..6df4a08e 100644 --- a/chapter5/src/main/java/nia.chapter5/package-info.java +++ b/chapter5/src/main/java/nia.chapter5/package-info.java @@ -1,7 +1,7 @@ /** * Created by kerr. * - * Listing 5.1 Backing array {@link nia.chapter5.ByteBufExamples#heapBuffer()} + * 代码清单 5-1 支撑数组 {@link nia.chapter5.ByteBufExamples#heapBuffer()} * * Listing 5.2 Direct buffer data access {@link nia.chapter5.ByteBufExamples#directBuffer()} * From 335056094ae1b8c9d2c44693093fd2803ab714d8 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 01:00:37 +0800 Subject: [PATCH 06/75] =?UTF-8?q?+=20=E7=AC=AC6=E7=AB=A0=E7=9A=84=E4=B8=AD?= =?UTF-8?q?=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nia.chapter5/package-info.java | 30 +++++++++---------- .../java/nia/chapter6/ChannelFutures.java | 4 +-- .../java/nia/chapter6/DiscardHandler.java | 5 ++-- .../nia/chapter6/DiscardInboundHandler.java | 4 ++- .../nia/chapter6/DiscardOutboundHandler.java | 5 +++- .../nia/chapter6/InboundExceptionHandler.java | 2 +- .../nia/chapter6/ModifyChannelPipeline.java | 12 ++++++-- .../chapter6/OutboundExceptionHandler.java | 2 +- .../java/nia/chapter6/SharableHandler.java | 4 ++- .../nia/chapter6/SimpleDiscardHandler.java | 4 ++- .../java/nia/chapter6/UnsharableHandler.java | 5 +++- .../main/java/nia/chapter6/WriteHandler.java | 4 ++- .../main/java/nia/chapter6/WriteHandlers.java | 16 ++++++---- .../main/java/nia/chapter6/package-info.java | 28 ++++++++--------- 14 files changed, 76 insertions(+), 49 deletions(-) diff --git a/chapter5/src/main/java/nia.chapter5/package-info.java b/chapter5/src/main/java/nia.chapter5/package-info.java index 6df4a08e..8a552432 100644 --- a/chapter5/src/main/java/nia.chapter5/package-info.java +++ b/chapter5/src/main/java/nia.chapter5/package-info.java @@ -3,34 +3,34 @@ * * 代码清单 5-1 支撑数组 {@link nia.chapter5.ByteBufExamples#heapBuffer()} * - * Listing 5.2 Direct buffer data access {@link nia.chapter5.ByteBufExamples#directBuffer()} + * 代码清单 5-2 访问直接缓冲区的数据 {@link nia.chapter5.ByteBufExamples#directBuffer()} * - * Listing 5.3 Composite buffer pattern using ByteBuffer {@link nia.chapter5.ByteBufExamples#byteBufferComposite(java.nio.ByteBuffer, java.nio.ByteBuffer)} + * 代码清单 5-3 使用 ByteBuffer 的复合缓冲区模式 {@link nia.chapter5.ByteBufExamples#byteBufferComposite(java.nio.ByteBuffer, java.nio.ByteBuffer)} * - * Listing 5.4 Composite buffer pattern using CompositeByteBuf {@link nia.chapter5.ByteBufExamples#byteBufComposite()} + * 代码清单 5-4 使用 CompositeByteBuf 的复合缓冲区模式 {@link nia.chapter5.ByteBufExamples#byteBufComposite()} * - * Listing 5.5 Accessing the data in a CompositeByteBuf {@link nia.chapter5.ByteBufExamples#byteBufCompositeArray()} + * 代码清单 5-5 访问 CompositeByteBuf {@link nia.chapter5.ByteBufExamples#byteBufCompositeArray()} * - * Listing 5.6 Access data {@link nia.chapter5.ByteBufExamples#byteBufRelativeAccess()} + * 代码清单 5-6 访问数据 {@link nia.chapter5.ByteBufExamples#byteBufRelativeAccess()} * - * Listing 5.7 Read all data {@link nia.chapter5.ByteBufExamples#readAllData()} + * 代码清单 5-7 读取所有数据 {@link nia.chapter5.ByteBufExamples#readAllData()} * - * Listing 5.8 Write data {@link nia.chapter5.ByteBufExamples#write()} + * 代码清单 5-8 写数据 {@link nia.chapter5.ByteBufExamples#write()} * - * Listing 5.9 Using ByteBufProcessor to find \r {@link nia.chapter5.ByteBufExamples#byteBufProcessor()} + * 代码清单 5-9 使用 ByteBufProcessor 来寻找\r {@link nia.chapter5.ByteBufExamples#byteBufProcessor()} * - * Listing 5.10 Slice a ByteBuf {@link nia.chapter5.ByteBufExamples#byteBufSlice()} + * 代码清单 5-10 对 ByteBuf 进行切片 {@link nia.chapter5.ByteBufExamples#byteBufSlice()} * - * Listing 5.11 Copying a ByteBuf {@link nia.chapter5.ByteBufExamples#byteBufCopy()} + * 代码清单 5-11 复制一个 ByteBuf {@link nia.chapter5.ByteBufExamples#byteBufCopy()} * - * Listing 5.12 get() and set() usage {@link nia.chapter5.ByteBufExamples#byteBufSetGet()} + * 代码清单 5-12 get()和 set()方法的用法 {@link nia.chapter5.ByteBufExamples#byteBufSetGet()} * - * Listing 5.13 read() and write() operations on the ByteBuf {@link nia.chapter5.ByteBufExamples#byteBufWriteRead()} + * 代码清单 5-13 ByteBuf 上的 read()和 write()操作 {@link nia.chapter5.ByteBufExamples#byteBufWriteRead()} * - * Listing 5.14 Obtaining a ByteBufAllocator reference {@link nia.chapter5.ByteBufExamples#obtainingByteBufAllocatorReference()} + * 代码清单 5-14 获取一个到 ByteBufAllocator 的引用 {@link nia.chapter5.ByteBufExamples#obtainingByteBufAllocatorReference()} * - * Listing 5.15 Reference counting {@link nia.chapter5.ByteBufExamples#referenceCounting()} + * 代码清单 5-15 引用计数 {@link nia.chapter5.ByteBufExamples#referenceCounting()} * - * Listing 5.16 Release reference-counted object {@link nia.chapter5.ByteBufExamples#releaseReferenceCountedObject()} + * 代码清单 5-16 释放引用计数的对象 {@link nia.chapter5.ByteBufExamples#releaseReferenceCountedObject()} */ package nia.chapter5; \ No newline at end of file diff --git a/chapter6/src/main/java/nia/chapter6/ChannelFutures.java b/chapter6/src/main/java/nia/chapter6/ChannelFutures.java index 5593fae4..358522ea 100644 --- a/chapter6/src/main/java/nia/chapter6/ChannelFutures.java +++ b/chapter6/src/main/java/nia/chapter6/ChannelFutures.java @@ -11,14 +11,14 @@ /** * Created by kerr. * - * Listing 6.13 Adding a ChannelFutureListener to a ChannelFuture + * 代码清单 6-13 添加 ChannelFutureListener 到 ChannelFuture */ public class ChannelFutures { private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); private static final ByteBuf SOME_MSG_FROM_SOMEWHERE = Unpooled.buffer(1024); /** - * Listing 6.13 Adding a ChannelFutureListener to a ChannelFuture + * 代码清单 6-13 添加 ChannelFutureListener 到 ChannelFuture * */ public static void addingChannelFutureListener(){ Channel channel = CHANNEL_FROM_SOMEWHERE; // get reference to pipeline; diff --git a/chapter6/src/main/java/nia/chapter6/DiscardHandler.java b/chapter6/src/main/java/nia/chapter6/DiscardHandler.java index 44fc040c..596eff82 100644 --- a/chapter6/src/main/java/nia/chapter6/DiscardHandler.java +++ b/chapter6/src/main/java/nia/chapter6/DiscardHandler.java @@ -6,15 +6,16 @@ import io.netty.util.ReferenceCountUtil; /** - * Listing 6.1 Releasing message resources + * 代码清单 6-1 释放消息资源 * * @author Norman Maurer */ @Sharable +//扩展了 ChannelInboundHandlerAdapter public class DiscardHandler extends ChannelInboundHandlerAdapter { - @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { + //丢弃已接收的消息 ReferenceCountUtil.release(msg); } diff --git a/chapter6/src/main/java/nia/chapter6/DiscardInboundHandler.java b/chapter6/src/main/java/nia/chapter6/DiscardInboundHandler.java index 985bf359..4a043cf8 100644 --- a/chapter6/src/main/java/nia/chapter6/DiscardInboundHandler.java +++ b/chapter6/src/main/java/nia/chapter6/DiscardInboundHandler.java @@ -6,14 +6,16 @@ import io.netty.util.ReferenceCountUtil; /** - * Listing 6.3 Consuming and releasing an inbound message + * 代码清单 6-3 消费并释放入站消息 * * @author Norman Maurer */ @Sharable +//扩展了ChannelInboundandlerAdapter public class DiscardInboundHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { + //通过调用 ReferenceCountUtil.release()方法释放资源 ReferenceCountUtil.release(msg); } } diff --git a/chapter6/src/main/java/nia/chapter6/DiscardOutboundHandler.java b/chapter6/src/main/java/nia/chapter6/DiscardOutboundHandler.java index 1043bce4..fe23641b 100644 --- a/chapter6/src/main/java/nia/chapter6/DiscardOutboundHandler.java +++ b/chapter6/src/main/java/nia/chapter6/DiscardOutboundHandler.java @@ -7,17 +7,20 @@ import io.netty.util.ReferenceCountUtil; /** - * Listing 6.4 Discarding and releasing outbound data + * 代码清单 6-4 丢弃并释放出站消息 * * @author Norman Maurer */ @Sharable +//扩展了ChannelOutboundHandlerAdapter public class DiscardOutboundHandler extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { + //通过使用 ReferenceCountUtil.realse(...)方法释放资源 ReferenceCountUtil.release(msg); + //通知 ChannelPromise数据已经被处理了 promise.setSuccess(); } } diff --git a/chapter6/src/main/java/nia/chapter6/InboundExceptionHandler.java b/chapter6/src/main/java/nia/chapter6/InboundExceptionHandler.java index d684dbad..7a62e264 100644 --- a/chapter6/src/main/java/nia/chapter6/InboundExceptionHandler.java +++ b/chapter6/src/main/java/nia/chapter6/InboundExceptionHandler.java @@ -4,7 +4,7 @@ import io.netty.channel.ChannelInboundHandlerAdapter; /** - * Listing 6.12 Basic inbound exception handling + * 代码清单 6-12 基本的入站异常处理 * * @author Norman Maurer */ diff --git a/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java b/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java index e9ddf56a..f134dc81 100644 --- a/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java +++ b/chapter6/src/main/java/nia/chapter6/ModifyChannelPipeline.java @@ -6,7 +6,7 @@ import static io.netty.channel.DummyChannelPipeline.DUMMY_INSTANCE; /** - * Listing 6.5 Modify the ChannelPipeline + * 代码清单 6-5 修改 ChannelPipeline * * @author Norman Maurer */ @@ -14,19 +14,25 @@ public class ModifyChannelPipeline { private static final ChannelPipeline CHANNEL_PIPELINE_FROM_SOMEWHERE = DUMMY_INSTANCE; /** - * Listing 6.5 Modify the ChannelPipeline + * 代码清单 6-5 修改 ChannelPipeline * */ public static void modifyPipeline() { ChannelPipeline pipeline = CHANNEL_PIPELINE_FROM_SOMEWHERE; // get reference to pipeline; + //创建一个 FirstHandler 的实例 FirstHandler firstHandler = new FirstHandler(); + //将该实例作为"handler1"添加到ChannelPipeline 中 pipeline.addLast("handler1", firstHandler); + //将一个 SecondHandler的实例作为"handler2"添加到 ChannelPipeline的第一个槽中。这意味着它将被放置在已有的"handler1"之前 pipeline.addFirst("handler2", new SecondHandler()); + //将一个 ThirdHandler 的实例作为"handler3"添加到 ChannelPipeline 的最后一个槽中 pipeline.addLast("handler3", new ThirdHandler()); //... + //通过名称移除"handler3" pipeline.remove("handler3"); + //通过引用移除FirstHandler(它是唯一的,所以不需要它的名称) pipeline.remove(firstHandler); + //将 SecondHandler("handler2")替换为 FourthHandler:"handler4" pipeline.replace("handler2", "handler4", new FourthHandler()); - } private static final class FirstHandler diff --git a/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java b/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java index 0afa8191..d4ae1918 100644 --- a/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java +++ b/chapter6/src/main/java/nia/chapter6/OutboundExceptionHandler.java @@ -3,7 +3,7 @@ import io.netty.channel.*; /** - * Listing 6.14 Adding a ChannelFutureListener to a ChannelPromise + * 代码清单 6-14 添加 ChannelFutureListener 到 ChannelPromise * * @author Norman Maurer */ diff --git a/chapter6/src/main/java/nia/chapter6/SharableHandler.java b/chapter6/src/main/java/nia/chapter6/SharableHandler.java index 46be4828..ab35577b 100644 --- a/chapter6/src/main/java/nia/chapter6/SharableHandler.java +++ b/chapter6/src/main/java/nia/chapter6/SharableHandler.java @@ -5,15 +5,17 @@ import io.netty.channel.ChannelInboundHandlerAdapter; /** - * Listing 6.10 A sharable ChannelHandler + * 代码清单 6-10 可共享的 ChannelHandler * * @author Norman Maurer */ +//使用注解@Sharable标注 @Sharable public class SharableHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { System.out.println("channel read message " + msg); + //记录方法调用,并转发给下一个 ChannelHandler ctx.fireChannelRead(msg); } } diff --git a/chapter6/src/main/java/nia/chapter6/SimpleDiscardHandler.java b/chapter6/src/main/java/nia/chapter6/SimpleDiscardHandler.java index 4292419c..b3466023 100644 --- a/chapter6/src/main/java/nia/chapter6/SimpleDiscardHandler.java +++ b/chapter6/src/main/java/nia/chapter6/SimpleDiscardHandler.java @@ -5,16 +5,18 @@ import io.netty.channel.SimpleChannelInboundHandler; /** - * Listing 6.2 Using SimpleChannelInboundHandler + * 代码清单 6-2 使用 SimpleChannelInboundHandler * * @author Norman Maurer */ @Sharable +//扩展了SimpleChannelInboundHandler public class SimpleDiscardHandler extends SimpleChannelInboundHandler { @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) { + //不需要任何显式的资源释放 // No need to do anything special } } diff --git a/chapter6/src/main/java/nia/chapter6/UnsharableHandler.java b/chapter6/src/main/java/nia/chapter6/UnsharableHandler.java index 3bb61450..a19b3276 100644 --- a/chapter6/src/main/java/nia/chapter6/UnsharableHandler.java +++ b/chapter6/src/main/java/nia/chapter6/UnsharableHandler.java @@ -5,16 +5,19 @@ import io.netty.channel.ChannelInboundHandlerAdapter; /** - * Listing 6.11 Invalid usage of @Sharable + * 代码清单 6-11 @Sharable 的错误用法 * * @author Norman Maurer */ +//使用注解@Sharable标注 @Sharable public class UnsharableHandler extends ChannelInboundHandlerAdapter { private int count; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { + //将 count 字段的值加 1 count++; + //记录方法调用,并转发给下一个ChannelHandler System.out.println("inboundBufferUpdated(...) called the " + count + " time"); ctx.fireChannelRead(msg); diff --git a/chapter6/src/main/java/nia/chapter6/WriteHandler.java b/chapter6/src/main/java/nia/chapter6/WriteHandler.java index f853b16b..b142e8c9 100644 --- a/chapter6/src/main/java/nia/chapter6/WriteHandler.java +++ b/chapter6/src/main/java/nia/chapter6/WriteHandler.java @@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext; /** - * Listing 6.9 Caching a ChannelHandlerContext + * 代码清单 6-9 缓存到 ChannelHandlerContext 的引用 * * @author Norman Maurer */ @@ -13,9 +13,11 @@ public class WriteHandler extends ChannelHandlerAdapter { private ChannelHandlerContext ctx; @Override public void handlerAdded(ChannelHandlerContext ctx) { + //存储到 ChannelHandlerContext的引用以供稍后使用 this.ctx = ctx; } public void send(String msg) { + //使用之前存储的到 ChannelHandlerContext的引用来发送消息 ctx.writeAndFlush(msg); } } diff --git a/chapter6/src/main/java/nia/chapter6/WriteHandlers.java b/chapter6/src/main/java/nia/chapter6/WriteHandlers.java index 24296a5d..cd0b69b4 100644 --- a/chapter6/src/main/java/nia/chapter6/WriteHandlers.java +++ b/chapter6/src/main/java/nia/chapter6/WriteHandlers.java @@ -12,9 +12,9 @@ /** * Created by kerr. * - * Listing 6.6 Accessing the Channel from a ChannelHandlerContext + * 代码清单 6-6 从 ChannelHandlerContext 访问 Channel * - * Listing 6.7 Accessing the ChannelPipeline from a ChannelHandlerContext + * 代码清单 6-7 通过 ChannelHandlerContext 访问 ChannelPipeline * * Listing 6.8 Calling ChannelHandlerContext write() */ @@ -23,32 +23,38 @@ public class WriteHandlers { private static final ChannelPipeline CHANNEL_PIPELINE_FROM_SOMEWHERE = DummyChannelPipeline.DUMMY_INSTANCE; /** - * Listing 6.6 Accessing the Channel from a ChannelHandlerContext + * 代码清单 6-6 从 ChannelHandlerContext 访问 Channel * */ public static void writeViaChannel() { ChannelHandlerContext ctx = CHANNEL_HANDLER_CONTEXT_FROM_SOMEWHERE; //get reference form somewhere + //获取到与 ChannelHandlerContext相关联的 Channel 的引用 Channel channel = ctx.channel(); + //通过 Channel 写入缓冲区 channel.write(Unpooled.copiedBuffer("Netty in Action", CharsetUtil.UTF_8)); } /** - * Listing 6.7 Accessing the ChannelPipeline from a ChannelHandlerContext + * 代码清单 6-7 通过 ChannelHandlerContext 访问 ChannelPipeline * */ public static void writeViaChannelPipeline() { ChannelHandlerContext ctx = CHANNEL_HANDLER_CONTEXT_FROM_SOMEWHERE; //get reference form somewhere + //获取到与 ChannelHandlerContext相关联的 ChannelPipeline 的引用 ChannelPipeline pipeline = ctx.pipeline(); //get reference form somewhere + //通过 ChannelPipeline写入缓冲区 pipeline.write(Unpooled.copiedBuffer("Netty in Action", CharsetUtil.UTF_8)); } /** - * Listing 6.8 Calling ChannelHandlerContext write() + * 代码清单 6-8 调用 ChannelHandlerContext 的 write()方法 * */ public static void writeViaChannelHandlerContext() { + //获取到 ChannelHandlerContext 的引用 ChannelHandlerContext ctx = CHANNEL_HANDLER_CONTEXT_FROM_SOMEWHERE; //get reference form somewhere; + //write()方法将把缓冲区数据发送到下一个 ChannelHandler ctx.write(Unpooled.copiedBuffer("Netty in Action", CharsetUtil.UTF_8)); } diff --git a/chapter6/src/main/java/nia/chapter6/package-info.java b/chapter6/src/main/java/nia/chapter6/package-info.java index 9fc4ea8b..5b0551d3 100644 --- a/chapter6/src/main/java/nia/chapter6/package-info.java +++ b/chapter6/src/main/java/nia/chapter6/package-info.java @@ -1,32 +1,32 @@ /** * Created by kerr. * - * Listing 6.1 Releasing message resources {@link nia.chapter6.DiscardHandler} + * 代码清单 6-1 释放消息资源 {@link nia.chapter6.DiscardHandler} * - * Listing 6.2 Using SimpleChannelInboundHandler {@link nia.chapter6.SimpleDiscardHandler} + * 代码清单 6-2 使用 SimpleChannelInboundHandler {@link nia.chapter6.SimpleDiscardHandler} * - * Listing 6.3 Consuming and releasing an inbound message {@link nia.chapter6.DiscardInboundHandler} + * 代码清单 6-3 消费并释放入站消息 {@link nia.chapter6.DiscardInboundHandler} * - * Listing 6.4 Discarding and releasing outbound data {@link nia.chapter6.DiscardOutboundHandler} + * 代码清单 6-4 丢弃并释放出站消息 {@link nia.chapter6.DiscardOutboundHandler} * - * Listing 6.5 Modify the ChannelPipeline {@link nia.chapter6.ModifyChannelPipeline#modifyPipeline()} + * 代码清单 6-5 修改 ChannelPipeline {@link nia.chapter6.ModifyChannelPipeline#modifyPipeline()} * - * Listing 6.6 Accessing the Channel from a ChannelHandlerContext {@link nia.chapter6.WriteHandlers#writeViaChannel()} + * 代码清单 6-6 从 ChannelHandlerContext 访问 Channel {@link nia.chapter6.WriteHandlers#writeViaChannel()} * - * Listing 6.7 Accessing the ChannelPipeline from a ChannelHandlerContext {@link nia.chapter6.WriteHandlers#writeViaChannelPipeline()} + * 代码清单 6-7 通过 ChannelHandlerContext 访问 ChannelPipeline {@link nia.chapter6.WriteHandlers#writeViaChannelPipeline()} * - * Listing 6.8 Calling ChannelHandlerContext write() {@link nia.chapter6.WriteHandlers#writeViaChannelHandlerContext()} + * 代码清单 6-8 调用 ChannelHandlerContext 的 write()方法 {@link nia.chapter6.WriteHandlers#writeViaChannelHandlerContext()} * - * Listing 6.9 Caching a ChannelHandlerContext {@link nia.chapter6.WriteHandler} + * 代码清单 6-9 缓存到 ChannelHandlerContext 的引用 {@link nia.chapter6.WriteHandler} * - * Listing 6.10 A sharable ChannelHandler {@link nia.chapter6.SharableHandler} + * 代码清单 6-10 可共享的 ChannelHandler {@link nia.chapter6.SharableHandler} * - * Listing 6.11 Invalid usage of @Sharable {@link nia.chapter6.UnsharableHandler} + * 代码清单 6-11 @Sharable 的错误用法 {@link nia.chapter6.UnsharableHandler} * - * Listing 6.12 Basic inbound exception handling {@link nia.chapter6.InboundExceptionHandler} + * 代码清单 6-12 基本的入站异常处理 {@link nia.chapter6.InboundExceptionHandler} * - * Listing 6.13 Adding a ChannelFutureListener to a ChannelFuture {@link nia.chapter6.ChannelFutures#addingChannelFutureListener()} + * 代码清单 6-13 添加 ChannelFutureListener 到 ChannelFuture {@link nia.chapter6.ChannelFutures#addingChannelFutureListener()} * - * Listing 6.14 Adding a ChannelFutureListener to a ChannelPromise {@link nia.chapter6.OutboundExceptionHandler} + * 代码清单 6-14 添加 ChannelFutureListener 到 ChannelPromise{@link nia.chapter6.OutboundExceptionHandler} */ package nia.chapter6; \ No newline at end of file From 1caacca13345f2ba1bfbcb74e1d3f5309aaab2f2 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 01:16:18 +0800 Subject: [PATCH 07/75] =?UTF-8?q?+=20=E7=AC=AC7=E7=AB=A0=E7=9A=84=E4=B8=AD?= =?UTF-8?q?=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nia/chapter7/EventLoopExamples.java | 6 ++-- .../java/nia/chapter7/ScheduleExamples.java | 36 +++++++++++++------ .../main/java/nia/chapter7/package-info.java | 10 +++--- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java b/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java index df172b0d..5a31535f 100644 --- a/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java +++ b/chapter7/src/main/java/nia/chapter7/EventLoopExamples.java @@ -4,20 +4,22 @@ import java.util.List; /** - * Listing 7.1 Executing tasks in an event loop + * 代码清单 7-1 在事件循环中执行任务 * * @author Norman Maurer */ public class EventLoopExamples { /** - * Listing 7.1 Executing tasks in an event loop + * 代码清单 7-1 在事件循环中执行任务 * */ public static void executeTaskInEventLoop() { boolean terminated = true; //... while (!terminated) { + //阻塞,直到有事件已经就绪可被运行 List readyEvents = blockUntilEventsReady(); for (Runnable ev: readyEvents) { + //循环遍历,并处理所有的事件 ev.run(); } } diff --git a/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java b/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java index 84147ec0..00f5423c 100644 --- a/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java +++ b/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java @@ -9,13 +9,13 @@ import java.util.concurrent.TimeUnit; /** - * Listing 7.2 Scheduling a task with a ScheduledExecutorService + * 代码清单 7-2 使用 ScheduledExecutorService 调度任务 * - * Listing 7.3 Scheduling a task with EventLoop + * 代码清单 7-3 使用 EventLoop 调度任务 * - * Listing 7.4 Scheduling a recurring task with EventLoop + * 代码清单 7-4 使用 EventLoop 调度周期性的任务 * - * Listing 7.5 Canceling a task using ScheduledFuture + * 代码清单 7-5 使用 ScheduledFuture 取消任务 * * @author Norman Maurer */ @@ -23,56 +23,69 @@ public class ScheduleExamples { private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); /** - * Listing 7.2 Scheduling a task with a ScheduledExecutorService + * 代码清单 7-2 使用 ScheduledExecutorService 调度任务 * */ public static void schedule() { + //创建一个其线程池具有 10 个线程的ScheduledExecutorService ScheduledExecutorService executor = Executors.newScheduledThreadPool(10); ScheduledFuture future = executor.schedule( + //创建一个 Runnable,以供调度稍后执行 new Runnable() { @Override public void run() { + //该任务要打印的消息 System.out.println("Now it is 60 seconds later"); } + //调度任务在从现在开始的 60 秒之后执行 }, 60, TimeUnit.SECONDS); //... + //一旦调度任务执行完成,就关闭 ScheduledExecutorService 以释放资源 executor.shutdown(); } /** - * Listing 7.3 Scheduling a task with EventLoop + * 代码清单 7-3 使用 EventLoop 调度任务 * */ public static void scheduleViaEventLoop() { Channel ch = CHANNEL_FROM_SOMEWHERE; // get reference from somewhere ScheduledFuture future = ch.eventLoop().schedule( + //创建一个 Runnable以供调度稍后执行 new Runnable() { @Override public void run() { + //要执行的代码 System.out.println("60 seconds later"); } + //调度任务在从现在开始的 60 秒之后执行 }, 60, TimeUnit.SECONDS); } /** - * Listing 7.4 Scheduling a recurring task with EventLoop + * 代码清单 7-4 使用 EventLoop 调度周期性的任务 * */ public static void scheduleFixedViaEventLoop() { Channel ch = CHANNEL_FROM_SOMEWHERE; // get reference from somewhere ScheduledFuture future = ch.eventLoop().scheduleAtFixedRate( + //创建一个 Runnable,以供调度稍后执行 new Runnable() { @Override public void run() { - System.out.println("Run every 60 seconds"); - } - }, 60, 60, TimeUnit.SECONDS); + //这将一直运行,直到 ScheduledFuture 被取消 + System.out.println("Run every 60 seconds"); + } + //调度在 60 秒之后,并且以后每间隔 60 秒运行 + }, 60, 60, TimeUnit.SECONDS); } /** - * Listing 7.5 Canceling a task using ScheduledFuture + * 代码清单 7-5 使用 ScheduledFuture 取消任务 * */ public static void cancelingTaskUsingScheduledFuture(){ Channel ch = CHANNEL_FROM_SOMEWHERE; // get reference from somewhere + //... + //调度任务,并获得所返回的ScheduledFuture ScheduledFuture future = ch.eventLoop().scheduleAtFixedRate( new Runnable() { @Override @@ -82,6 +95,7 @@ public void run() { }, 60, 60, TimeUnit.SECONDS); // Some other code that runs... boolean mayInterruptIfRunning = false; + //取消该任务,防止它再次运行 future.cancel(mayInterruptIfRunning); } } diff --git a/chapter7/src/main/java/nia/chapter7/package-info.java b/chapter7/src/main/java/nia/chapter7/package-info.java index 5bbc4798..3d7af680 100644 --- a/chapter7/src/main/java/nia/chapter7/package-info.java +++ b/chapter7/src/main/java/nia/chapter7/package-info.java @@ -1,14 +1,14 @@ /** * Created by kerr. * - * Listing 7.1 Executing tasks in an event loop {@link nia.chapter7.EventLoopExamples#executeTaskInEventLoop()} + * 代码清单 7-1 在事件循环中执行任务 {@link nia.chapter7.EventLoopExamples#executeTaskInEventLoop()} * - * Listing 7.2 Scheduling a task with a ScheduledExecutorService {@link nia.chapter7.ScheduleExamples#schedule()} + * 代码清单 7-2 使用 ScheduledExecutorService 调度任务 {@link nia.chapter7.ScheduleExamples#schedule()} * - * Listing 7.3 Scheduling a task with EventLoop {@link nia.chapter7.ScheduleExamples#scheduleViaEventLoop()} + * 代码清单 7-3 使用 EventLoop 调度任务 {@link nia.chapter7.ScheduleExamples#scheduleViaEventLoop()} * - * Listing 7.4 Scheduling a recurring task with EventLoop {@link nia.chapter7.ScheduleExamples#scheduleFixedViaEventLoop()} + * 代码清单 7-4 使用 EventLoop 调度周期性的任务 {@link nia.chapter7.ScheduleExamples#scheduleFixedViaEventLoop()} * - * Listing 7.5 Canceling a task using ScheduledFuture {@link nia.chapter7.ScheduleExamples#cancelingTaskUsingScheduledFuture()} + * 代码清单 7-5 使用 ScheduledFuture 取消任务 {@link nia.chapter7.ScheduleExamples#cancelingTaskUsingScheduledFuture()} */ package nia.chapter7; \ No newline at end of file From 7bee4fb9d425c241aebc6ef4e2047c9de8c2c7ff Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 02:22:05 +0800 Subject: [PATCH 08/75] =?UTF-8?q?+=20=E7=AC=AC8=E7=AB=A0=E7=9A=84=E4=B8=AD?= =?UTF-8?q?=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/nia/chapter8/BootstrapClient.java | 14 +++++++++----- .../BootstrapClientWithOptionsAndAttrs.java | 13 +++++++++++-- .../nia/chapter8/BootstrapDatagramChannel.java | 9 +++++++-- .../main/java/nia/chapter8/BootstrapServer.java | 9 +++++++-- .../chapter8/BootstrapSharingEventLoopGroup.java | 15 +++++++++++++-- .../nia/chapter8/BootstrapWithInitializer.java | 11 +++++++++-- .../main/java/nia/chapter8/GracefulShutdown.java | 7 +++++-- .../nia/chapter8/InvalidBootstrapClient.java | 14 ++++++++++---- .../src/main/java/nia/chapter8/package-info.java | 16 ++++++++-------- 9 files changed, 79 insertions(+), 29 deletions(-) diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapClient.java b/chapter8/src/main/java/nia/chapter8/BootstrapClient.java index 223a15a4..fa6cfc29 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapClient.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapClient.java @@ -9,7 +9,7 @@ import java.net.InetSocketAddress; /** - * Listing 8.1 Bootstrapping a client + * 代码清单 8-1 引导一个客户端 * * @author Norman Maurer * @author Marvin Wolfthal @@ -21,13 +21,17 @@ public static void main(String args[]) { } /** - * Listing 8.1 Bootstrapping a client + * 代码清单 8-1 引导一个客户端 * */ public void bootstrap() { + //设置 EventLoopGroup,提供用于处理 Channel 事件的 EventLoop EventLoopGroup group = new NioEventLoopGroup(); + //创建一个Bootstrap类的实例以创建和连接新的客户端Channel Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) + //指定要使用的Channel 实现 .channel(NioSocketChannel.class) + //设置用于 Channel 事件和数据的ChannelInboundHandler .handler(new SimpleChannelInboundHandler() { @Override protected void channelRead0( @@ -36,9 +40,9 @@ protected void channelRead0( System.out.println("Received data"); } }); - ChannelFuture future = - bootstrap.connect( - new InetSocketAddress("www.manning.com", 80)); + //连接到远程主机 + ChannelFuture future = bootstrap.connect( + new InetSocketAddress("www.manning.com", 80)); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapClientWithOptionsAndAttrs.java b/chapter8/src/main/java/nia/chapter8/BootstrapClientWithOptionsAndAttrs.java index 0ccbafec..fccf12f5 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapClientWithOptionsAndAttrs.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapClientWithOptionsAndAttrs.java @@ -13,25 +13,31 @@ import java.net.InetSocketAddress; /** - * Listing 8.7 Using attributes + * 代码清单 8-7 使用属性值 * * @author Norman Maurer */ public class BootstrapClientWithOptionsAndAttrs { /** - * Listing 8.7 Using attributes + * 代码清单 8-7 使用属性值 * */ public void bootstrap() { + //创建一个 AttributeKey 以标识该属性 final AttributeKey id = AttributeKey.newInstance("ID"); + //创建一个 Bootstrap 类的实例以创建客户端 Channel 并连接它们 Bootstrap bootstrap = new Bootstrap(); + //设置 EventLoopGroup,其提供了用以处理 Channel 事件的 EventLoop bootstrap.group(new NioEventLoopGroup()) + //指定 Channel 的实现 .channel(NioSocketChannel.class) .handler( + //设置用以处理 Channel 的 I/O 以及数据的 ChannelInboundHandler new SimpleChannelInboundHandler() { @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + //使用 AttributeKey 检索属性以及它的值 Integer idValue = ctx.channel().attr(id).get(); // do something with the idValue } @@ -44,9 +50,12 @@ protected void channelRead0( } } ); + //设置 ChannelOption,其将在 connect()或者bind()方法被调用时被设置到已经创建的 Channel 上 bootstrap.option(ChannelOption.SO_KEEPALIVE, true) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); + //存储该 id 属性 bootstrap.attr(id, 123456); + //使用配置好的 Bootstrap 实例连接到远程主机 ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); future.syncUninterruptibly(); diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java b/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java index 89acc2f2..3830bf68 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapDatagramChannel.java @@ -12,7 +12,7 @@ import java.net.InetSocketAddress; /** - * Listing 8.8 Using Bootstrap with DatagramChannel + * 代码清单 8-8 使用 Bootstrap 和 DatagramChannel * * @author Norman Maurer * @author Marvin Wolfthal @@ -20,12 +20,16 @@ public class BootstrapDatagramChannel { /** - * Listing 8.8 Using Bootstrap with DatagramChannel + * 代码清单 8-8 使用 Bootstrap 和 DatagramChannel */ public void bootstrap() { + //创建一个 Bootstrap 的实例以创建和绑定新的数据报 Channel Bootstrap bootstrap = new Bootstrap(); + //设置 EventLoopGroup,其提供了用以处理 Channel 事件的 EventLoop bootstrap.group(new OioEventLoopGroup()).channel( + //指定 Channel 的实现 OioDatagramChannel.class).handler( + //设置用以处理 Channel 的 I/O 以及数据的 ChannelInboundHandler new SimpleChannelInboundHandler() { @Override public void channelRead0(ChannelHandlerContext ctx, @@ -34,6 +38,7 @@ public void channelRead0(ChannelHandlerContext ctx, } } ); + //调用 bind() 方法,因为该协议是无连接的 ChannelFuture future = bootstrap.bind(new InetSocketAddress(0)); future.addListener(new ChannelFutureListener() { @Override diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapServer.java b/chapter8/src/main/java/nia/chapter8/BootstrapServer.java index d88b20ad..08e3f6a9 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapServer.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapServer.java @@ -12,7 +12,7 @@ import java.net.InetSocketAddress; /** - * Listing 8.4 Bootstrapping a server + * 代码清单 8-4 引导服务器 * * @author Norman Maurer * @author Marvin Wolfthal @@ -20,13 +20,17 @@ public class BootstrapServer { /** - * Listing 8.4 Bootstrapping a server + * 代码清单 8-4 引导服务器 * */ public void bootstrap() { NioEventLoopGroup group = new NioEventLoopGroup(); + //创建 Server Bootstrap ServerBootstrap bootstrap = new ServerBootstrap(); + //设置 EventLoopGroup,其提供了用于处理 Channel 事件的EventLoop bootstrap.group(group) + //指定要使用的 Channel 实现 .channel(NioServerSocketChannel.class) + //设置用于处理已被接受的子 Channel 的I/O及数据的 ChannelInboundHandler .childHandler(new SimpleChannelInboundHandler() { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, @@ -34,6 +38,7 @@ protected void channelRead0(ChannelHandlerContext channelHandlerContext, System.out.println("Received data"); } }); + //通过配置好的 ServerBootstrap 的实例绑定该 Channel ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); future.addListener(new ChannelFutureListener() { @Override diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapSharingEventLoopGroup.java b/chapter8/src/main/java/nia/chapter8/BootstrapSharingEventLoopGroup.java index 650deeb8..e8e91d6f 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapSharingEventLoopGroup.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapSharingEventLoopGroup.java @@ -14,7 +14,7 @@ import java.net.InetSocketAddress; /** - * Listing 8.5 Bootstrapping a server + * 代码清单 8-5 引导服务器 * * @author Norman Maurer * @author Marvin Wolfthal @@ -22,20 +22,27 @@ public class BootstrapSharingEventLoopGroup { /** - * Listing 8.5 Bootstrapping a server + * 代码清单 8-5 引导服务器 * */ public void bootstrap() { + //创建 ServerBootstrap 以创建 ServerSocketChannel,并绑定它 ServerBootstrap bootstrap = new ServerBootstrap(); + //设置 EventLoopGroup,其将提供用以处理 Channel 事件的 EventLoop bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()) + //指定要使用的 Channel 实现 .channel(NioServerSocketChannel.class) + //设置用于处理已被接受的子 Channel 的 I/O 和数据的 ChannelInboundHandler .childHandler( new SimpleChannelInboundHandler() { ChannelFuture connectFuture; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { + //创建一个 Bootstrap 类的实例以连接到远程主机 Bootstrap bootstrap = new Bootstrap(); + //指定 Channel 的实现 bootstrap.channel(NioSocketChannel.class).handler( + //为入站 I/O 设置 ChannelInboundHandler new SimpleChannelInboundHandler() { @Override protected void channelRead0( @@ -44,8 +51,10 @@ protected void channelRead0( System.out.println("Received data"); } }); + //使用与分配给已被接受的子Channel相同的EventLoop bootstrap.group(ctx.channel().eventLoop()); connectFuture = bootstrap.connect( + //连接到远程节点 new InetSocketAddress("www.manning.com", 80)); } @@ -54,10 +63,12 @@ protected void channelRead0( ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { if (connectFuture.isDone()) { + //当连接完成时,执行一些数据操作(如代理) // do something with the data } } }); + //通过配置好的 ServerBootstrap 绑定该 ServerSocketChannel ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); future.addListener(new ChannelFutureListener() { @Override diff --git a/chapter8/src/main/java/nia/chapter8/BootstrapWithInitializer.java b/chapter8/src/main/java/nia/chapter8/BootstrapWithInitializer.java index b742f82a..5a420b67 100644 --- a/chapter8/src/main/java/nia/chapter8/BootstrapWithInitializer.java +++ b/chapter8/src/main/java/nia/chapter8/BootstrapWithInitializer.java @@ -10,26 +10,33 @@ import java.net.InetSocketAddress; /** - * Listing 8.6 Bootstrapping and using ChannelInitializer + * 代码清单 8-6 引导和使用 ChannelInitializer * * @author Norman Maurer */ public class BootstrapWithInitializer { /** - * Listing 8.6 Bootstrapping and using ChannelInitializer + * 代码清单 8-6 引导和使用 ChannelInitializer * */ public void bootstrap() throws InterruptedException { + //创建 ServerBootstrap 以创建和绑定新的 Channel ServerBootstrap bootstrap = new ServerBootstrap(); + //设置 EventLoopGroup,其将提供用以处理 Channel 事件的 EventLoop bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()) + //指定 Channel 的实现 .channel(NioServerSocketChannel.class) + //注册一个 ChannelInitializerImpl 的实例来设置 ChannelPipeline .childHandler(new ChannelInitializerImpl()); + //绑定到地址 ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); future.sync(); } + //用以设置 ChannelPipeline 的自定义 ChannelInitializerImpl 实现 final class ChannelInitializerImpl extends ChannelInitializer { @Override + //将所需的 ChannelHandler 添加到 ChannelPipeline protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpClientCodec()); diff --git a/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java b/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java index aa4d7d63..9c06a2d0 100644 --- a/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java +++ b/chapter8/src/main/java/nia/chapter8/GracefulShutdown.java @@ -10,7 +10,7 @@ import java.net.InetSocketAddress; /** - * Listing 8.9 Graceful shutdown + * 代码清单 8-9 优雅关闭 * * @author Norman Maurer * @author Marvin Wolfthal @@ -22,10 +22,12 @@ public static void main(String args[]) { } /** - * Listing 8.9 Graceful shutdown + * 代码清单 8-9 优雅关闭 */ public void bootstrap() { + //创建处理 I/O 的EventLoopGroup EventLoopGroup group = new NioEventLoopGroup(); + //创建一个 Bootstrap 类的实例并配置它 Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) @@ -42,6 +44,7 @@ protected void channelRead0( ); bootstrap.connect(new InetSocketAddress("www.manning.com", 80)).syncUninterruptibly(); //,,, + //shutdownGracefully()方法将释放所有的资源,并且关闭所有的当前正在使用中的 Channel Future future = group.shutdownGracefully(); // block until the group has shutdown future.syncUninterruptibly(); diff --git a/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java b/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java index e2273a1c..149b5a44 100644 --- a/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java +++ b/chapter8/src/main/java/nia/chapter8/InvalidBootstrapClient.java @@ -12,7 +12,7 @@ import java.net.InetSocketAddress; /** - * Listing 8.3 Incompatible Channel and EventLoopGroup + * 代码清单 8-3 不兼容的 Channel 和 EventLoopGroup * * @author Norman Maurer */ @@ -24,13 +24,18 @@ public static void main(String args[]) { } /** - * Listing 8.3 Incompatible Channel and EventLoopGroup + * 代码清单 8-3 不兼容的 Channel 和 EventLoopGroup * */ public void bootstrap() { EventLoopGroup group = new NioEventLoopGroup(); + //创建一个新的 Bootstrap 类的实例,以创建新的客户端Channel Bootstrap bootstrap = new Bootstrap(); - bootstrap.group(group).channel(OioSocketChannel.class) - .handler(new SimpleChannelInboundHandler() { + //指定一个适用于 NIO 的 EventLoopGroup 实现 + bootstrap.group(group) + //指定一个适用于 OIO 的 Channel 实现类 + .channel(OioSocketChannel.class) + //设置一个用于处理 Channel的 I/O 事件和数据的 ChannelInboundHandler + .handler(new SimpleChannelInboundHandler() { @Override protected void channelRead0( ChannelHandlerContext channelHandlerContext, @@ -38,6 +43,7 @@ protected void channelRead0( System.out.println("Received data"); } }); + //尝试连接到远程节点 ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); future.syncUninterruptibly(); diff --git a/chapter8/src/main/java/nia/chapter8/package-info.java b/chapter8/src/main/java/nia/chapter8/package-info.java index 5268dc34..91b53cd6 100644 --- a/chapter8/src/main/java/nia/chapter8/package-info.java +++ b/chapter8/src/main/java/nia/chapter8/package-info.java @@ -1,20 +1,20 @@ /** * Created by kerr. * - * Listing 8.1 Bootstrapping a client {@link nia.chapter8.BootstrapClient#bootstrap()} + * Listing 代码清单 8-1 引导一个客户端 {@link nia.chapter8.BootstrapClient#bootstrap()} * - * Listing 8.3 Incompatible Channel and EventLoopGroup {@link nia.chapter8.InvalidBootstrapClient#bootstrap()} + * 代码清单 8-3 不兼容的 Channel 和 EventLoopGroup {@link nia.chapter8.InvalidBootstrapClient#bootstrap()} * - * Listing 8.4 Bootstrapping a server{@link nia.chapter8.BootstrapServer#bootstrap()} + * 代码清单 8-4 引导服务器 {@link nia.chapter8.BootstrapServer#bootstrap()} * - * Listing 8.5 Bootstrapping a server {@link nia.chapter8.BootstrapSharingEventLoopGroup#bootstrap()} + * 代码清单 8-5 引导服务器 {@link nia.chapter8.BootstrapSharingEventLoopGroup#bootstrap()} * - * Listing 8.6 Bootstrapping and using ChannelInitializer {@link nia.chapter8.BootstrapWithInitializer#bootstrap()} + * 代码清单 8-6 引导和使用 ChannelInitializer {@link nia.chapter8.BootstrapWithInitializer#bootstrap()} * - * Listing 8.7 Using attributes {@link nia.chapter8.BootstrapClientWithOptionsAndAttrs#bootstrap()} + * 代码清单 8-7 使用属性值 {@link nia.chapter8.BootstrapClientWithOptionsAndAttrs#bootstrap()} * - * Listing 8.8 Using Bootstrap with DatagramChannel {@link nia.chapter8.BootstrapDatagramChannel#bootstrap()} + * 代码清单 8-8 使用 Bootstrap 和 DatagramChannel {@link nia.chapter8.BootstrapDatagramChannel#bootstrap()} * - * Listing 8.9 Graceful shutdown {@link nia.chapter8.GracefulShutdown#bootstrap()} + * 代码清单 8-9 优雅关闭 {@link nia.chapter8.GracefulShutdown#bootstrap()} */ package nia.chapter8; \ No newline at end of file From 49f0d65f0e4c8c9c7e805164ba1b20a9dd37c52b Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 02:44:56 +0800 Subject: [PATCH 09/75] =?UTF-8?q?+=20=E7=AC=AC9=E7=AB=A0=E7=9A=84=E4=B8=AD?= =?UTF-8?q?=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/nia/chapter9/AbsIntegerEncoder.java | 6 +++++- .../java/nia/chapter9/FixedLengthFrameDecoder.java | 7 ++++++- .../src/main/java/nia/chapter9/FrameChunkDecoder.java | 7 ++++++- chapter9/src/main/java/nia/chapter9/package-info.java | 6 +++--- .../java/nia/test/chapter9/AbsIntegerEncoderTest.java | 7 ++++++- .../test/chapter9/FixedLengthFrameDecoderTest.java | 11 ++++++++++- .../java/nia/test/chapter9/FrameChunkDecoderTest.java | 10 +++++++++- .../src/test/java/nia/test/chapter9/package-info.java | 6 +++--- 8 files changed, 48 insertions(+), 12 deletions(-) diff --git a/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java b/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java index e18d8e7f..d1913b51 100644 --- a/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java +++ b/chapter9/src/main/java/nia/chapter9/AbsIntegerEncoder.java @@ -7,17 +7,21 @@ import java.util.List; /** - * Listing 9.3 AbsIntegerEncoder + * 代码清单9-3 AbsIntegerEncoder * * @author Norman Maurer */ +//扩展 MessageToMessageEncoder 以将一个消息编码为另外一种格式 public class AbsIntegerEncoder extends MessageToMessageEncoder { @Override protected void encode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List out) throws Exception { + //检查是否有足够的字节用来编码 while (in.readableBytes() >= 4) { + //从输入的 ByteBuf中读取下一个整数,并且计算其绝对值 int value = Math.abs(in.readInt()); + //将该整数写入到编码消息的 List 中 out.add(value); } } diff --git a/chapter9/src/main/java/nia/chapter9/FixedLengthFrameDecoder.java b/chapter9/src/main/java/nia/chapter9/FixedLengthFrameDecoder.java index 3fd54c08..4eb8011d 100644 --- a/chapter9/src/main/java/nia/chapter9/FixedLengthFrameDecoder.java +++ b/chapter9/src/main/java/nia/chapter9/FixedLengthFrameDecoder.java @@ -7,13 +7,15 @@ import java.util.List; /** - * Listing 9.1 FixedLengthFrameDecoder + * 代码清单9-1 FixedLengthFrameDecoder * * @author Norman Maurer */ +//扩展 ByteToMessageDecoder 以处理入站字节,并将它们解码为消息 public class FixedLengthFrameDecoder extends ByteToMessageDecoder { private final int frameLength; + //指定要生成的帧的长度 public FixedLengthFrameDecoder(int frameLength) { if (frameLength <= 0) { throw new IllegalArgumentException( @@ -25,8 +27,11 @@ public FixedLengthFrameDecoder(int frameLength) { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + //检查是否有足够的字节可以被读取,以生成下一个帧 while (in.readableBytes() >= frameLength) { + //从 ByteBuf 中读取一个新帧 ByteBuf buf = in.readBytes(frameLength); + //将该帧添加到已被解码的消息列表中 out.add(buf); } } diff --git a/chapter9/src/main/java/nia/chapter9/FrameChunkDecoder.java b/chapter9/src/main/java/nia/chapter9/FrameChunkDecoder.java index caa5a408..85adc32d 100644 --- a/chapter9/src/main/java/nia/chapter9/FrameChunkDecoder.java +++ b/chapter9/src/main/java/nia/chapter9/FrameChunkDecoder.java @@ -8,13 +8,15 @@ import java.util.List; /** - * Listing 9.5 FrameChunkDecoder + * 代码清单9-5 FrameChunkDecoder * * @author Norman Maurer */ +//扩展 ByteToMessageDecoder以将入站字节解码为消息 public class FrameChunkDecoder extends ByteToMessageDecoder { private final int maxFrameSize; + //指定将要产生的帧的最大允许大小 public FrameChunkDecoder(int maxFrameSize) { this.maxFrameSize = maxFrameSize; } @@ -26,10 +28,13 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, int readableBytes = in.readableBytes(); if (readableBytes > maxFrameSize) { // discard the bytes + //如果该帧太大,则丢弃它并抛出一个 TooLongFrameException…… in.clear(); throw new TooLongFrameException(); } + //……否则,从 ByteBuf 中读取一个新的帧 ByteBuf buf = in.readBytes(readableBytes); + //将该帧添加到解码 读取一个新的帧消息的 List 中 out.add(buf); } } diff --git a/chapter9/src/main/java/nia/chapter9/package-info.java b/chapter9/src/main/java/nia/chapter9/package-info.java index 9ee9cd40..8442632c 100644 --- a/chapter9/src/main/java/nia/chapter9/package-info.java +++ b/chapter9/src/main/java/nia/chapter9/package-info.java @@ -1,10 +1,10 @@ /** * Created by kerr. * - * Listing 9.1 FixedLengthFrameDecoder {@link nia.chapter9.FixedLengthFrameDecoder} + * 代码清单9-1 FixedLengthFrameDecoder {@link nia.chapter9.FixedLengthFrameDecoder} * - * Listing 9.3 AbsIntegerEncoder {@link nia.chapter9.AbsIntegerEncoder} + * 代码清单9-3 AbsIntegerEncoder {@link nia.chapter9.AbsIntegerEncoder} * - * Listing 9.5 FrameChunkDecoder {@link nia.chapter9.FrameChunkDecoder} + * 代码清单9-5 FrameChunkDecoder {@link nia.chapter9.FrameChunkDecoder} */ package nia.chapter9; \ No newline at end of file diff --git a/chapter9/src/test/java/nia/test/chapter9/AbsIntegerEncoderTest.java b/chapter9/src/test/java/nia/test/chapter9/AbsIntegerEncoderTest.java index f07feb4b..6e1baef5 100644 --- a/chapter9/src/test/java/nia/test/chapter9/AbsIntegerEncoderTest.java +++ b/chapter9/src/test/java/nia/test/chapter9/AbsIntegerEncoderTest.java @@ -9,24 +9,29 @@ import static org.junit.Assert.*; /** - * Listing 9.4 Testing the AbsIntegerEncoder + * 代码清单9-4 测试 AbsIntegerEncoder * * @author Norman Maurer */ public class AbsIntegerEncoderTest { @Test public void testEncoded() { + //(1) 创建一个 ByteBuf,并且写入 9 个负整数 ByteBuf buf = Unpooled.buffer(); for (int i = 1; i < 10; i++) { buf.writeInt(i * -1); } + //(2) 创建一个EmbeddedChannel,并安装一个要测试的 AbsIntegerEncoder EmbeddedChannel channel = new EmbeddedChannel( new AbsIntegerEncoder()); + //(3) 写入 ByteBuf,并断言调用 readOutbound()方法将会产生数据 assertTrue(channel.writeOutbound(buf)); + //(4) 将该 Channel 标记为已完成状态 assertTrue(channel.finish()); // read bytes + //(5) 读取所产生的消息,并断言它们包含了对应的绝对值 for (int i = 1; i < 10; i++) { assertEquals(i, channel.readOutbound()); } diff --git a/chapter9/src/test/java/nia/test/chapter9/FixedLengthFrameDecoderTest.java b/chapter9/src/test/java/nia/test/chapter9/FixedLengthFrameDecoderTest.java index fda1349a..fc9c3326 100644 --- a/chapter9/src/test/java/nia/test/chapter9/FixedLengthFrameDecoderTest.java +++ b/chapter9/src/test/java/nia/test/chapter9/FixedLengthFrameDecoderTest.java @@ -9,25 +9,32 @@ import static org.junit.Assert.*; /** - * Listing 9.2 Testing the FixedLengthFrameDecoder + * 代码清单9-2 测试 FixedLengthFrameDecoder * * @author Norman Maurer */ public class FixedLengthFrameDecoderTest { + //使用了注解@Test 标注,因此 JUnit 将会执行该方法 @Test + //第一个测试方法:testFramesDecoded() public void testFramesDecoded() { + //创建一个 ByteBuf,并存储 9 字节 ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { buf.writeByte(i); } ByteBuf input = buf.duplicate(); + //创建一个EmbeddedChannel,并添加一个FixedLengthFrameDecoder,其将以 3 字节的帧长度被测试 EmbeddedChannel channel = new EmbeddedChannel( new FixedLengthFrameDecoder(3)); // write bytes + //将数据写入EmbeddedChannel assertTrue(channel.writeInbound(input.retain())); + //标记 Channel 为已完成状态 assertTrue(channel.finish()); // read messages + //读取所生成的消息,并且验证是否有 3 帧(切片),其中每帧(切片)都为 3 字节 ByteBuf read = (ByteBuf) channel.readInbound(); assertEquals(buf.readSlice(3), read); read.release(); @@ -45,6 +52,7 @@ public void testFramesDecoded() { } @Test + //第二个测试方法:testFramesDecoded2() public void testFramesDecoded2() { ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { @@ -54,6 +62,7 @@ public void testFramesDecoded2() { EmbeddedChannel channel = new EmbeddedChannel( new FixedLengthFrameDecoder(3)); + //返回 false,因为没有一个完整的可供读取的帧 assertFalse(channel.writeInbound(input.readBytes(2))); assertTrue(channel.writeInbound(input.readBytes(7))); diff --git a/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java b/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java index afb883b3..48bb4c28 100644 --- a/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java +++ b/chapter9/src/test/java/nia/test/chapter9/FrameChunkDecoderTest.java @@ -11,7 +11,7 @@ import static org.junit.Assert.*; /** - * Listing 9.6 Testing FrameChunkDecoder + * 代码清单9-6 测试 FrameChunkDecoder * * @author Norman Maurer */ @@ -19,26 +19,34 @@ public class FrameChunkDecoderTest { @Test public void testFramesDecoded() { + //创建一个 ByteBuf,并向它写入 9 字节 ByteBuf buf = Unpooled.buffer(); for (int i = 0; i < 9; i++) { buf.writeByte(i); } ByteBuf input = buf.duplicate(); + //创建一个 EmbeddedChannel,并向其安装一个帧大小为 3 字节的 FixedLengthFrameDecoder EmbeddedChannel channel = new EmbeddedChannel( new FrameChunkDecoder(3)); + //向它写入 2 字节,并断言它们将会产生一个新帧 assertTrue(channel.writeInbound(input.readBytes(2))); try { + //写入一个 4 字节大小的帧,并捕获预期的TooLongFrameException channel.writeInbound(input.readBytes(4)); + //如果上面没有 们将会产生一个新帧抛出异常,那么就会到达这个断言,并且测试失败 Assert.fail(); } catch (TooLongFrameException e) { // expected exception } + //写入剩余的2字节,并断言将会产生一个有效帧 assertTrue(channel.writeInbound(input.readBytes(3))); + //将该 Channel 标记为已完成状态 assertTrue(channel.finish()); // Read frames + //读取产生的消息,并且验证值 ByteBuf read = (ByteBuf) channel.readInbound(); assertEquals(buf.readSlice(2), read); read.release(); diff --git a/chapter9/src/test/java/nia/test/chapter9/package-info.java b/chapter9/src/test/java/nia/test/chapter9/package-info.java index ccfd2d7a..72573428 100644 --- a/chapter9/src/test/java/nia/test/chapter9/package-info.java +++ b/chapter9/src/test/java/nia/test/chapter9/package-info.java @@ -1,10 +1,10 @@ /** * Created by kerr. * - * Listing 9.2 Testing the FixedLengthFrameDecoder {@link nia.test.chapter9.FixedLengthFrameDecoderTest} + * 代码清单9-2 测试 FixedLengthFrameDecoder {@link nia.test.chapter9.FixedLengthFrameDecoderTest} * - * Listing 9.4 Testing the AbsIntegerEncoder {@link nia.test.chapter9.AbsIntegerEncoderTest} + * 代码清单9-4 测试 AbsIntegerEncoder {@link nia.test.chapter9.AbsIntegerEncoderTest} * - * Listing 9.6 Testing FrameChunkDecoder {@link nia.test.chapter9.FrameChunkDecoderTest} + * 代码清单9-6 测试 FrameChunkDecoder {@link nia.test.chapter9.FrameChunkDecoderTest} */ package nia.test.chapter9; \ No newline at end of file From ba0e5f27f9600a4652bc46d696b541d65b5a4902 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 03:20:34 +0800 Subject: [PATCH 10/75] =?UTF-8?q?+=20=E7=AC=AC10=E7=AB=A0=E7=9A=84?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nia/chapter10/ByteToCharDecoder.java | 4 +++- .../java/nia/chapter10/CharToByteEncoder.java | 4 +++- .../nia/chapter10/CombinedByteCharCodec.java | 5 +++-- .../nia/chapter10/IntegerToStringDecoder.java | 4 +++- .../nia/chapter10/IntegerToStringEncoder.java | 4 +++- .../chapter10/SafeByteToMessageDecoder.java | 6 ++++-- .../nia/chapter10/ShortToByteEncoder.java | 4 +++- .../java/nia/chapter10/ToIntegerDecoder.java | 5 ++++- .../java/nia/chapter10/ToIntegerDecoder2.java | 6 ++++-- .../chapter10/WebSocketConvertHandler.java | 7 ++++++- .../main/java/nia/chapter10/package-info.java | 20 +++++++++---------- 11 files changed, 46 insertions(+), 23 deletions(-) diff --git a/chapter10/src/main/java/nia/chapter10/ByteToCharDecoder.java b/chapter10/src/main/java/nia/chapter10/ByteToCharDecoder.java index 6a9793f9..2f4618e4 100644 --- a/chapter10/src/main/java/nia/chapter10/ByteToCharDecoder.java +++ b/chapter10/src/main/java/nia/chapter10/ByteToCharDecoder.java @@ -7,15 +7,17 @@ import java.util.List; /** - * Listing 10.8 Class ByteToCharDecoder + * 代码清单 10-8 ByteToCharDecoder 类 * * @author Norman Maurer */ +//扩展了ByteToMessageDecoder public class ByteToCharDecoder extends ByteToMessageDecoder { @Override public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { if (in.readableBytes() >= 2) { + //将一个或者多个 Character 对象添加到传出的 List 中 out.add(in.readChar()); } } diff --git a/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java b/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java index 966b658b..3fdde074 100644 --- a/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java +++ b/chapter10/src/main/java/nia/chapter10/CharToByteEncoder.java @@ -5,15 +5,17 @@ import io.netty.handler.codec.MessageToByteEncoder; /** - * Listing 10.9 Class CharToByteEncoder + * 代码清单 9 CharToByteEncoder 类 * * @author Norman Maurer */ +//扩展了MessageToByteEncoder public class CharToByteEncoder extends MessageToByteEncoder { @Override public void encode(ChannelHandlerContext ctx, Character msg, ByteBuf out) throws Exception { + //将 Character 解码为 char,并将其写入到出站 ByteBuf 中 out.writeChar(msg); } } diff --git a/chapter10/src/main/java/nia/chapter10/CombinedByteCharCodec.java b/chapter10/src/main/java/nia/chapter10/CombinedByteCharCodec.java index 5068df53..039baf88 100644 --- a/chapter10/src/main/java/nia/chapter10/CombinedByteCharCodec.java +++ b/chapter10/src/main/java/nia/chapter10/CombinedByteCharCodec.java @@ -3,14 +3,15 @@ import io.netty.channel.CombinedChannelDuplexHandler; /** - * Listing 10.10 CombinedChannelDuplexHandler + * 代码清单 CombinedChannelDuplexHandler * * @author Norman Maurer */ - +//通过该解码器和编码器实现参数化 CombinedByteCharCodec public class CombinedByteCharCodec extends CombinedChannelDuplexHandler { public CombinedByteCharCodec() { + //将委托实例传递给父类 super(new ByteToCharDecoder(), new CharToByteEncoder()); } } diff --git a/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java b/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java index bccbf693..73d06175 100644 --- a/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java +++ b/chapter10/src/main/java/nia/chapter10/IntegerToStringDecoder.java @@ -6,15 +6,17 @@ import java.util.List; /** - * Listing 10.3 Class IntegerToStringDecoder + * 代码清单 10-3 IntegerToStringDecoder 类 * * @author Norman Maurer */ +//扩展了MessageToMessageDecoder public class IntegerToStringDecoder extends MessageToMessageDecoder { @Override public void decode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { + //将 Integer 消息转换为它的 String 表示,并将其添加到输出的 List 中 out.add(String.valueOf(msg)); } } diff --git a/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java b/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java index 6c6390da..58afa464 100644 --- a/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java +++ b/chapter10/src/main/java/nia/chapter10/IntegerToStringEncoder.java @@ -6,15 +6,17 @@ import java.util.List; /** - * Listing 10.6 Class IntegerToStringEncoder + * 代码清单 10-6 IntegerToStringEncoder 类 * * @author Norman Maurer */ +//扩展了 MessageToMessageEncoder public class IntegerToStringEncoder extends MessageToMessageEncoder { @Override public void encode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { + //将 Integer 转换为 String,并将其添加到 List 中 out.add(String.valueOf(msg)); } } diff --git a/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java b/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java index 6328cd28..04ffe513 100644 --- a/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java +++ b/chapter10/src/main/java/nia/chapter10/SafeByteToMessageDecoder.java @@ -8,18 +8,20 @@ import java.util.List; /** - * Listing 10.4 TooLongFrameException + * 代码清单 10-4 TooLongFrameException * * @author Norman Maurer */ - +//扩展 ByteToMessageDecoder 以将字节解码为消息 public class SafeByteToMessageDecoder extends ByteToMessageDecoder { private static final int MAX_FRAME_SIZE = 1024; @Override public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { int readable = in.readableBytes(); + //检查缓冲区中是否有超过 MAX_FRAME_SIZE 个字节 if (readable > MAX_FRAME_SIZE) { + //跳过所有的可读字节,抛出 TooLongFrameException 并通知 ChannelHandler in.skipBytes(readable); throw new TooLongFrameException("Frame too big!"); } diff --git a/chapter10/src/main/java/nia/chapter10/ShortToByteEncoder.java b/chapter10/src/main/java/nia/chapter10/ShortToByteEncoder.java index 51e5b80c..5c7d3bad 100644 --- a/chapter10/src/main/java/nia/chapter10/ShortToByteEncoder.java +++ b/chapter10/src/main/java/nia/chapter10/ShortToByteEncoder.java @@ -5,14 +5,16 @@ import io.netty.handler.codec.MessageToByteEncoder; /** - * Listing 10.5 Class ShortToByteEncoder + * 代码清单 10-5 ShortToByteEncoder 类 * * @author Norman Maurer */ +//扩展了MessageToByteEncoder public class ShortToByteEncoder extends MessageToByteEncoder { @Override public void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out) throws Exception { + //将 Short 写入 ByteBuf 中 out.writeShort(msg); } } diff --git a/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder.java b/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder.java index 48235e76..10991689 100644 --- a/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder.java +++ b/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder.java @@ -7,15 +7,18 @@ import java.util.List; /** - * Listing 10.1 Class ToIntegerDecoder extends ByteToMessageDecoder + * 代码清单 10-1 ToIntegerDecoder 类扩展了 ByteToMessageDecoder * * @author Norman Maurer */ +//扩展ByteToMessageDecoder类,以将字节解码为特定的格式 public class ToIntegerDecoder extends ByteToMessageDecoder { @Override public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + //检查是否至少有 4 字节可读(一个 int 的字节长度) if (in.readableBytes() >= 4) { + //从入站 ByteBuf 中读取一个 int,并将其添加到解码消息的 List 中 out.add(in.readInt()); } } diff --git a/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java b/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java index 52a0157a..53fba55b 100644 --- a/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java +++ b/chapter10/src/main/java/nia/chapter10/ToIntegerDecoder2.java @@ -7,15 +7,17 @@ import java.util.List; /** - * Listing 10.2 Class ToIntegerDecoder2 extends ReplayingDecoder + * 代码清单 10-2 ToIntegerDecoder2 类扩展了 ReplayingDecoder * * @author Norman Maurer */ +//扩展 ReplayingDecoder 以将字节解码为消息 public class ToIntegerDecoder2 extends ReplayingDecoder { @Override - public void decode(ChannelHandlerContext ctx, ByteBuf in, + public void decode(ChannelHandlerContext ctx, ByteBuf in, //传入的 ByteBuf 是 ReplayingDecoderByteBuf List out) throws Exception { + //从入站 ByteBuf 中读取 一个 int,并将其添加到解码消息的 List 中 out.add(in.readInt()); } } diff --git a/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java b/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java index dc5a3f52..7bfba048 100644 --- a/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java +++ b/chapter10/src/main/java/nia/chapter10/WebSocketConvertHandler.java @@ -9,7 +9,7 @@ import java.util.List; /** - * Listing 10.7 Using MessageToMessageCodec + * 代码清单 10-7 使用 MessageToMessageCodec * * @author Norman Maurer */ @@ -18,10 +18,12 @@ public class WebSocketConvertHandler extends MessageToMessageCodec { @Override + //将 MyWebSocketFrame 编码为指定的 WebSocketFrame 子类型 protected void encode(ChannelHandlerContext ctx, WebSocketConvertHandler.MyWebSocketFrame msg, List out) throws Exception { ByteBuf payload = msg.getData().duplicate().retain(); + //实例化一个指定子类型的 WebSocketFrame switch (msg.getType()) { case BINARY: out.add(new BinaryWebSocketFrame(payload)); @@ -47,6 +49,7 @@ protected void encode(ChannelHandlerContext ctx, } @Override + //将 WebSocketFrame 解码为 MyWebSocketFrame,并设置 FrameType protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List out) throws Exception { ByteBuf payload = msg.content().duplicate().retain(); @@ -80,7 +83,9 @@ protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, } } + //声明 WebSocketConvertHandler 所使用的 OUTBOUND_IN 类型 public static final class MyWebSocketFrame { + //定义拥有被包装的有效负载的 WebSocketFrame 的类型 public enum FrameType { BINARY, CLOSE, diff --git a/chapter10/src/main/java/nia/chapter10/package-info.java b/chapter10/src/main/java/nia/chapter10/package-info.java index d5f47fa7..1df510c5 100644 --- a/chapter10/src/main/java/nia/chapter10/package-info.java +++ b/chapter10/src/main/java/nia/chapter10/package-info.java @@ -1,24 +1,24 @@ /** * Created by kerr. * - * Listing 10.1 Class ToIntegerDecoder extends ByteToMessageDecoder {@link nia.chapter10.ToIntegerDecoder} + * 代码清单 10-1 ToIntegerDecoder 类扩展了 ByteToMessageDecoder {@link nia.chapter10.ToIntegerDecoder} * - * Listing 10.2 Class ToIntegerDecoder2 extends ReplayingDecoder {@link nia.chapter10.ToIntegerDecoder2} + * 代码清单 10-2 ToIntegerDecoder2 类扩展了 ReplayingDecoder {@link nia.chapter10.ToIntegerDecoder2} * - * Listing 10.3 Class IntegerToStringDecoder {@link nia.chapter10.IntegerToStringDecoder} + * 代码清单 10-3 IntegerToStringDecoder 类 {@link nia.chapter10.IntegerToStringDecoder} * - * Listing 10.4 TooLongFrameException {@link nia.chapter10.SafeByteToMessageDecoder} + * 代码清单 10-4 TooLongFrameException {@link nia.chapter10.SafeByteToMessageDecoder} * - * Listing 10.5 Class ShortToByteEncoder {@link nia.chapter10.ShortToByteEncoder} + * 代码清单 10-5 ShortToByteEncoder 类 {@link nia.chapter10.ShortToByteEncoder} * - * Listing 10.6 Class IntegerToStringEncoder {@link nia.chapter10.IntegerToStringEncoder} + * 代码清单 10-6 IntegerToStringEncoder 类 {@link nia.chapter10.IntegerToStringEncoder} * - * Listing 10.7 Using MessageToMessageCodec {@link nia.chapter10.WebSocketConvertHandler} + * 代码清单 10-7 使用 MessageToMessageCodec {@link nia.chapter10.WebSocketConvertHandler} * - * Listing 10.8 Class ByteToCharDecoder {@link nia.chapter10.ByteToCharDecoder} + * 代码清单 10-8 ByteToCharDecoder 类 {@link nia.chapter10.ByteToCharDecoder} * - * Listing 10.9 Class CharToByteEncoder {@link nia.chapter10.CharToByteEncoder} + * 代码清单 9 CharToByteEncoder 类 {@link nia.chapter10.CharToByteEncoder} * - * Listing 10.10 CombinedChannelDuplexHandler {@link nia.chapter10.CombinedByteCharCodec} + * 代码清单 CombinedChannelDuplexHandler {@link nia.chapter10.CombinedByteCharCodec} */ package nia.chapter10; \ No newline at end of file From f91b9d13911e5b7f113068df210ae64e9fbdb182 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 03:54:30 +0800 Subject: [PATCH 11/75] =?UTF-8?q?+=20=E7=AC=AC11=E7=AB=A0=E7=9A=84?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ChunkedWriteHandlerInitializer.java | 6 +++- .../nia/chapter11/CmdHandlerInitializer.java | 11 +++++++- .../nia/chapter11/FileRegionWriteHandler.java | 6 +++- .../chapter11/HttpAggregatorInitializer.java | 5 +++- .../chapter11/HttpCompressionInitializer.java | 6 +++- .../chapter11/HttpPipelineInitializer.java | 6 +++- .../nia/chapter11/HttpsCodecInitializer.java | 5 +++- .../IdleStateHandlerInitializer.java | 8 +++++- .../nia/chapter11/LengthBasedInitializer.java | 5 +++- .../LineBasedHandlerInitializer.java | 5 +++- .../nia/chapter11/MarshallingInitializer.java | 5 +++- .../nia/chapter11/ProtoBufInitializer.java | 6 +++- .../nia/chapter11/SslChannelInitializer.java | 8 ++++-- .../chapter11/WebSocketServerInitializer.java | 7 ++++- .../main/java/nia/chapter11/package-info.java | 28 +++++++++---------- 15 files changed, 87 insertions(+), 30 deletions(-) diff --git a/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java index fcde7c2d..9df741a6 100644 --- a/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/ChunkedWriteHandlerInitializer.java @@ -10,7 +10,7 @@ import java.io.FileInputStream; /** - * Listing 11.12 of Netty in Action + * 代码清单 11-12 使用 ChunkedStream 传输文件内容 * * @author Norman Maurer */ @@ -26,8 +26,11 @@ public ChunkedWriteHandlerInitializer(File file, SslContext sslCtx) { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); + //将 SslHandler 添加到 ChannelPipeline 中 pipeline.addLast(new SslHandler(sslCtx.newEngine(ch.alloc()))); + //添加 ChunkedWriteHandler 以处理作为 ChunkedInput 传入的数据 pipeline.addLast(new ChunkedWriteHandler()); + //一旦连接建立,WriteStreamHandler 就开始写文件数据 pipeline.addLast(new WriteStreamHandler()); } @@ -35,6 +38,7 @@ public final class WriteStreamHandler extends ChannelInboundHandlerAdapter { @Override + //当连接建立时,channelActive() 方法将使用 ChunkedInput 写文件数据 public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); diff --git a/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java index 1ab893fc..bd4cca08 100644 --- a/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/CmdHandlerInitializer.java @@ -5,7 +5,7 @@ import io.netty.handler.codec.LineBasedFrameDecoder; /** - * Listing 11.9 Using a ChannelInitializer as a decoder installer + * 代码清单 11-9 使用 ChannelInitializer 安装解码器 * * @author Norman Maurer */ @@ -14,10 +14,13 @@ public class CmdHandlerInitializer extends ChannelInitializer { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); + //添加 CmdDecoder 以提取 Cmd 对象,并将它转发给下一个 ChannelInboundHandler pipeline.addLast(new CmdDecoder(64 * 1024)); + //添加 CmdHandler 以接收和处理 Cmd 对象 pipeline.addLast(new CmdHandler()); } + //Cmd POJO public static final class Cmd { private final ByteBuf name; private final ByteBuf args; @@ -44,12 +47,17 @@ public CmdDecoder(int maxLength) { @Override protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception { + //从 ByteBuf 中提取由行尾符序列分隔的帧 ByteBuf frame = (ByteBuf) super.decode(ctx, buffer); if (frame == null) { + //如果输入中没有帧,则返回 null + return null; } + //查找第一个空格字符的索引。前面是命令名称,接着是参数 int index = frame.indexOf(frame.readerIndex(), frame.writerIndex(), SPACE); + //使用包含有命令名称和参数的切片创建新的 Cmd 对象 return new Cmd(frame.slice(frame.readerIndex(), index), frame.slice(index + 1, frame.writerIndex())); } @@ -61,6 +69,7 @@ public static final class CmdHandler public void channelRead0(ChannelHandlerContext ctx, Cmd msg) throws Exception { // Do something with the command + //处理传经 ChannelPipeline 的 Cmd 对象 } } } diff --git a/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java b/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java index 13f65b39..44af7204 100644 --- a/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java +++ b/chapter11/src/main/java/nia/chapter11/FileRegionWriteHandler.java @@ -9,7 +9,7 @@ /** * Created by kerr. * - * Listing 11.11 Transferring file contents with FileRegion + * 代码清单 11-11 使用 FileRegion 传输文件的内容 */ public class FileRegionWriteHandler extends ChannelInboundHandlerAdapter { private static final Channel CHANNEL_FROM_SOMEWHERE = new NioSocketChannel(); @@ -20,15 +20,19 @@ public void channelActive(final ChannelHandlerContext ctx) throws Exception { File file = FILE_FROM_SOMEWHERE; //get reference from somewhere Channel channel = CHANNEL_FROM_SOMEWHERE; //get reference from somewhere //... + //创建一个 FileInputStream FileInputStream in = new FileInputStream(file); + //以该文件的完整长度创建一个新的 DefaultFileRegion FileRegion region = new DefaultFileRegion( in.getChannel(), 0, file.length()); + //发送该 DefaultFileRegion,并注册一个 ChannelFutureListener channel.writeAndFlush(region).addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { + //处理失败 Throwable cause = future.cause(); // Do something } diff --git a/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java index 83944191..f86a5bd5 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpAggregatorInitializer.java @@ -8,7 +8,7 @@ import io.netty.handler.codec.http.HttpServerCodec; /** - * Listing 11.3 Automatically aggregating HTTP message fragments + * 代码清单 11-3 自动聚合 HTTP 的消息片段 * * @author Norman Maurer */ @@ -23,10 +23,13 @@ public HttpAggregatorInitializer(boolean isClient) { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (isClient) { + //如果是客户端,则添加 HttpClientCodec pipeline.addLast("codec", new HttpClientCodec()); } else { + //如果是服务器,则添加 HttpServerCodec pipeline.addLast("codec", new HttpServerCodec()); } + //将最大的消息大小为 512 KB 的 HttpObjectAggregator 添加到 ChannelPipeline pipeline.addLast("aggregator", new HttpObjectAggregator(512 * 1024)); } diff --git a/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java index 9c6ece23..60182023 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpCompressionInitializer.java @@ -9,7 +9,7 @@ import io.netty.handler.codec.http.HttpServerCodec; /** - * Listing 11.4 Automatically compressing HTTP messages + * 代码清单 11-4 自动压缩 HTTP 消息 * * @author Norman Maurer */ @@ -24,11 +24,15 @@ public HttpCompressionInitializer(boolean isClient) { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (isClient) { + //如果是客户端,则添加 HttpClientCodec pipeline.addLast("codec", new HttpClientCodec()); + //如果是客户端,则添加 HttpContentDecompressor 以处理来自服务器的压缩内容 pipeline.addLast("decompressor", new HttpContentDecompressor()); } else { + //如果是服务器,则添加 HttpServerCodec pipeline.addLast("codec", new HttpServerCodec()); + //如果是服务器,则添加HttpContentCompressor 来压缩数据(如果客户端支持它) pipeline.addLast("compressor", new HttpContentCompressor()); } diff --git a/chapter11/src/main/java/nia/chapter11/HttpPipelineInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpPipelineInitializer.java index aa9afd9f..fa392622 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpPipelineInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpPipelineInitializer.java @@ -9,7 +9,7 @@ import io.netty.handler.codec.http.HttpResponseEncoder; /** - * Listing 11.2 Adding support for HTTP + * 代码清单 11-2 添加 HTTP 支持 * * @author Norman Maurer */ @@ -25,10 +25,14 @@ public HttpPipelineInitializer(boolean client) { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); if (client) { + //如果是客户端,则添加 HttpResponseDecoder 以处理来自服务器的响应 pipeline.addLast("decoder", new HttpResponseDecoder()); + //如果是客户端,则添加 HttpRequestEncoder 以向服务器发送请求 pipeline.addLast("encoder", new HttpRequestEncoder()); } else { + //如果是服务器,则添加 HttpRequestDecoder 以接收来自客户端的请求 pipeline.addLast("decoder", new HttpRequestDecoder()); + //如果是服务器,则添加 HttpResponseEncoder 以向客户端发送响应 pipeline.addLast("encoder", new HttpResponseEncoder()); } } diff --git a/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java b/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java index 78e1f7ac..6c2aee0a 100644 --- a/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/HttpsCodecInitializer.java @@ -11,7 +11,7 @@ import javax.net.ssl.SSLEngine; /** - * Listing 11.5 Using HTTPS + * 代码清单 11-5 使用 HTTPS * * @author Norman Maurer */ @@ -28,11 +28,14 @@ public HttpsCodecInitializer(SslContext context, boolean isClient) { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); SSLEngine engine = context.newEngine(ch.alloc()); + //将 SslHandler 添加到ChannelPipeline 中以使用 HTTPS pipeline.addFirst("ssl", new SslHandler(engine)); if (isClient) { + //如果是客户端,则添加 HttpClientCodec pipeline.addLast("codec", new HttpClientCodec()); } else { + //如果是服务器,则添加 HttpServerCodec pipeline.addLast("codec", new HttpServerCodec()); } } diff --git a/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java index f00b8e05..d168f3d5 100644 --- a/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/IdleStateHandlerInitializer.java @@ -10,7 +10,7 @@ import java.util.concurrent.TimeUnit; /** - * Listing 11.7 Sending heartbeats + * 代码清单 11-7 发送心跳 * * @author Norman Maurer */ @@ -20,23 +20,29 @@ public class IdleStateHandlerInitializer extends ChannelInitializer protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast( + //(1) IdleStateHandler 将在被触发时发送一个IdleStateEvent 事件 new IdleStateHandler(0, 0, 60, TimeUnit.SECONDS)); + //将一个 HeartbeatHandler 添加到ChannelPipeline中 pipeline.addLast(new HeartbeatHandler()); } + //实现 userEventTriggered() 方法以发送心跳消息 public static final class HeartbeatHandler extends ChannelInboundHandlerAdapter { + //发送到远程节点的心跳消息 private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer( "HEARTBEAT", CharsetUtil.ISO_8859_1)); @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + //(2) 发送心跳消息,并在发送失败时关闭该连接 if (evt instanceof IdleStateEvent) { ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()) .addListener( ChannelFutureListener.CLOSE_ON_FAILURE); } else { + //不是 IdleStateEvent 事件,所以将它传递给下一个 ChannelInboundHandler super.userEventTriggered(ctx, evt); } } diff --git a/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java b/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java index a1d0fb14..143efda5 100644 --- a/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/LengthBasedInitializer.java @@ -5,7 +5,7 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder; /** - * Listing 11.10 Decoder for the command and the handler + * 代码清单 11-10 使用 LengthFieldBasedFrameDecoder 解码器基于长度的协议 * * @author Norman Maurer */ @@ -14,7 +14,9 @@ public class LengthBasedInitializer extends ChannelInitializer { protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast( + //使用 LengthFieldBasedFrameDecoder 解码将帧长度编码到帧起始的前 8 个字节中的消息 new LengthFieldBasedFrameDecoder(64 * 1024, 0, 8)); + //添加 FrameHandler 以处理每个帧 pipeline.addLast(new FrameHandler()); } @@ -24,6 +26,7 @@ public static final class FrameHandler public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { // Do something with the frame + //处理帧的数据 } } } diff --git a/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java b/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java index 652d020b..e37003aa 100644 --- a/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/LineBasedHandlerInitializer.java @@ -5,7 +5,7 @@ import io.netty.handler.codec.LineBasedFrameDecoder; /** - * Listing 11.8 Handling line-delimited frames + * 代码清单 11-8 处理由行尾符分隔的帧 * * @author Norman Maurer */ @@ -14,13 +14,16 @@ public class LineBasedHandlerInitializer extends ChannelInitializer @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); + //该 LineBasedFrameDecoder 将提取的帧转发给下一个 ChannelInboundHandler pipeline.addLast(new LineBasedFrameDecoder(64 * 1024)); + //添加 FrameHandler 以接收帧 pipeline.addLast(new FrameHandler()); } public static final class FrameHandler extends SimpleChannelInboundHandler { @Override + //传入了单个帧的内容 public void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { // Do something with the data extracted from the frame diff --git a/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java b/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java index c027a629..d7a3c3e5 100644 --- a/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/MarshallingInitializer.java @@ -9,7 +9,7 @@ import java.io.Serializable; /** - * Listing 11.13 Using JBoss Marshalling + * 代码清单 11-13 使用 JBoss Marshalling * * @author Norman Maurer */ @@ -27,8 +27,11 @@ public MarshallingInitializer( @Override protected void initChannel(Channel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); + //添加 MarshallingDecoder 以将 ByteBuf 转换为 POJO pipeline.addLast(new MarshallingDecoder(unmarshallerProvider)); + //添加 MarshallingEncoder 以将POJO 转换为 ByteBuf pipeline.addLast(new MarshallingEncoder(marshallerProvider)); + //添加 ObjectHandler,以处理普通的实现了Serializable 接口的 POJO pipeline.addLast(new ObjectHandler()); } diff --git a/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java b/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java index e5b77e06..b7aea095 100644 --- a/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/ProtoBufInitializer.java @@ -7,7 +7,7 @@ import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; /** - * Listing 11.14 Using protobuf + * 代码清单 11-14 使用 protobuf * * @author Norman Maurer */ @@ -21,9 +21,13 @@ public ProtoBufInitializer(MessageLite lite) { @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); + //添加 ProtobufVarint32FrameDecoder 以分隔帧 pipeline.addLast(new ProtobufVarint32FrameDecoder()); + //添加 ProtobufEncoder 以处理消息的编码 pipeline.addLast(new ProtobufEncoder()); + //添加 ProtobufDecoder 以解码消息 pipeline.addLast(new ProtobufDecoder(lite)); + //添加 ObjectHandler 以处理解码消息 pipeline.addLast(new ObjectHandler()); } diff --git a/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java b/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java index 55f95aac..cdfac579 100644 --- a/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/SslChannelInitializer.java @@ -8,7 +8,7 @@ import javax.net.ssl.SSLEngine; /** - * Listing 11.1 Adding SSL/TLS support + * 代码清单 11-1 添加 SSL/TLS 支持 * * @author Norman Maurer */ @@ -16,14 +16,16 @@ public class SslChannelInitializer extends ChannelInitializer { private final SslContext context; private final boolean startTls; - public SslChannelInitializer(SslContext context, - boolean startTls) { + public SslChannelInitializer(SslContext context, //传入要使用的 SslContext + boolean startTls) { //如果设置为 true,第一个写入的消息将不会被加密(客户端应该设置为 true) this.context = context; this.startTls = startTls; } @Override protected void initChannel(Channel ch) throws Exception { + //对于每个 SslHandler 实例,都使用 Channel 的 ByteBufAllocator 从 SslContext 获取一个新的 SSLEngine SSLEngine engine = context.newEngine(ch.alloc()); + //将 SslHandler 作为第一个 ChannelHandler 添加到 ChannelPipeline 中 ch.pipeline().addFirst("ssl", new SslHandler(engine, startTls)); } diff --git a/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java b/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java index cbced5ef..3bc635ce 100644 --- a/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java +++ b/chapter11/src/main/java/nia/chapter11/WebSocketServerInitializer.java @@ -12,7 +12,7 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; /** - * Listing 11.6 Supporting WebSocket on the server + * 代码清单 11-6 在服务器端支持 WebSocket * * @author Norman Maurer */ @@ -21,10 +21,15 @@ public class WebSocketServerInitializer extends ChannelInitializer { protected void initChannel(Channel ch) throws Exception { ch.pipeline().addLast( new HttpServerCodec(), + //为握手提供聚合的 HttpRequest new HttpObjectAggregator(65536), + //如果被请求的端点是"/websocket",则处理该升级握手 new WebSocketServerProtocolHandler("/websocket"), + //TextFrameHandler 处理 TextWebSocketFrame new TextFrameHandler(), + //BinaryFrameHandler 处理 BinaryWebSocketFrame new BinaryFrameHandler(), + //ContinuationFrameHandler 处理 ContinuationWebSocketFrame new ContinuationFrameHandler()); } diff --git a/chapter11/src/main/java/nia/chapter11/package-info.java b/chapter11/src/main/java/nia/chapter11/package-info.java index 1f9c3a47..04ca3330 100644 --- a/chapter11/src/main/java/nia/chapter11/package-info.java +++ b/chapter11/src/main/java/nia/chapter11/package-info.java @@ -1,32 +1,32 @@ /** * Created by kerr. * - * Listing 11.1 Adding SSL/TLS support {@link nia.chapter11.SslChannelInitializer} + * 代码清单 11-1 添加 SSL/TLS 支持 {@link nia.chapter11.SslChannelInitializer} * - * Listing 11.2 Adding support for HTTP {@link nia.chapter11.HttpPipelineInitializer} + * 代码清单 11-2 添加 HTTP 支持 {@link nia.chapter11.HttpPipelineInitializer} * - * Listing 11.3 Automatically aggregating HTTP message fragments {@link nia.chapter11.HttpAggregatorInitializer} + * 代码清单 11-3 自动聚合 HTTP 的消息片段 {@link nia.chapter11.HttpAggregatorInitializer} * - * Listing 11.4 Automatically compressing HTTP messages {@link nia.chapter11.HttpCompressionInitializer} + * 代码清单 11-4 自动压缩 HTTP 消息 {@link nia.chapter11.HttpCompressionInitializer} * - * Listing 11.5 Using HTTPS {@link nia.chapter11.HttpsCodecInitializer} + * 代码清单 11-5 使用 HTTPS {@link nia.chapter11.HttpsCodecInitializer} * - * Listing 11.6 Supporting WebSocket on the server {@link nia.chapter11.WebSocketServerInitializer} + * 代码清单 11-6 在服务器端支持 WebSocket {@link nia.chapter11.WebSocketServerInitializer} * - * Listing 11.7 Sending heartbeats {@link nia.chapter11.IdleStateHandlerInitializer} + * 代码清单 11-7 发送心跳 {@link nia.chapter11.IdleStateHandlerInitializer} * - * Listing 11.8 Handling line-delimited frames {@link nia.chapter11.LineBasedHandlerInitializer} + * 代码清单 11-8 处理由行尾符分隔的帧 {@link nia.chapter11.LineBasedHandlerInitializer} * - * Listing 11.9 Using a ChannelInitializer as a decoder installer {@link nia.chapter11.CmdHandlerInitializer} + * 代码清单 11-9 使用 ChannelInitializer 安装解码器 {@link nia.chapter11.CmdHandlerInitializer} * - * Listing 11.10 Decoder for the command and the handler {@link nia.chapter11.LengthBasedInitializer} + * 代码清单 11-10 使用 LengthFieldBasedFrameDecoder 解码器基于长度的协议 {@link nia.chapter11.LengthBasedInitializer} * - * Listing 11.11 Transferring file contents with FileRegion {@link nia.chapter11.FileRegionWriteHandler} + * 代码清单 11-11 使用 FileRegion 传输文件的内容 {@link nia.chapter11.FileRegionWriteHandler} * - * Listing 11.12 Transferring file contents with ChunkedStream {@link nia.chapter11.ChunkedWriteHandlerInitializer} + * 代码清单 11-12 使用 ChunkedStream 传输文件内容 {@link nia.chapter11.ChunkedWriteHandlerInitializer} * - * Listing 11.13 Using JBoss Marshalling {@link nia.chapter11.MarshallingInitializer} + * 代码清单 11-13 使用 JBoss Marshalling {@link nia.chapter11.MarshallingInitializer} * - * Listing 11.14 Using protobuf {@link nia.chapter11.ProtoBufInitializer} + * 代码清单 11-14 使用 protobuf {@link nia.chapter11.ProtoBufInitializer} */ package nia.chapter11; \ No newline at end of file From 5592c5554c493fc2b565f17c043a65fc39ddf2ac Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 04:09:49 +0800 Subject: [PATCH 12/75] =?UTF-8?q?+=20=E7=AC=AC12=E7=AB=A0=E7=9A=84?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/nia/chapter12/ChatServer.java | 6 +++++- .../java/nia/chapter12/ChatServerInitializer.java | 4 +++- .../main/java/nia/chapter12/HttpRequestHandler.java | 11 ++++++++++- .../main/java/nia/chapter12/SecureChatServer.java | 4 +++- .../nia/chapter12/SecureChatServerInitializer.java | 5 ++++- .../nia/chapter12/TextWebSocketFrameHandler.java | 8 +++++++- .../src/main/java/nia/chapter12/package-info.java | 12 ++++++------ 7 files changed, 38 insertions(+), 12 deletions(-) diff --git a/chapter12/src/main/java/nia/chapter12/ChatServer.java b/chapter12/src/main/java/nia/chapter12/ChatServer.java index 837e5811..c28e4f65 100644 --- a/chapter12/src/main/java/nia/chapter12/ChatServer.java +++ b/chapter12/src/main/java/nia/chapter12/ChatServer.java @@ -14,17 +14,19 @@ import java.net.InetSocketAddress; /** - * Listing 12.4 Bootstrapping the server + * 代码清单 12-4 引导服务器 * * @author Norman Maurer */ public class ChatServer { + //创建 DefaultChannelGroup,其将保存所有已经连接的 WebSocket Channel private final ChannelGroup channelGroup = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE); private final EventLoopGroup group = new NioEventLoopGroup(); private Channel channel; public ChannelFuture start(InetSocketAddress address) { + //引导服务器 ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(group) .channel(NioServerSocketChannel.class) @@ -35,11 +37,13 @@ public ChannelFuture start(InetSocketAddress address) { return future; } + //创建 ChatServerInitializer protected ChannelInitializer createInitializer( ChannelGroup group) { return new ChatServerInitializer(group); } + //处理服务器关闭,并释放所有的资源 public void destroy() { if (channel != null) { channel.close(); diff --git a/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java b/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java index 3316a8d8..04dccdb8 100644 --- a/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java +++ b/chapter12/src/main/java/nia/chapter12/ChatServerInitializer.java @@ -10,10 +10,11 @@ import io.netty.handler.stream.ChunkedWriteHandler; /** - * Listing 12.3 Initializing the ChannelPipeline + * 代码清单 12-3 初始化 ChannelPipeline * * @author Norman Maurer */ +//扩展了 ChannelInitializer public class ChatServerInitializer extends ChannelInitializer { private final ChannelGroup group; @@ -22,6 +23,7 @@ public ChatServerInitializer(ChannelGroup group) { } @Override + //将所有需要的 ChannelHandler 添加到 ChannelPipeline 中 protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); diff --git a/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java b/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java index b781cde0..2ee0b391 100644 --- a/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java +++ b/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java @@ -11,10 +11,11 @@ import java.net.URL; /** - * Listing 12.1 HTTPRequestHandler + * 代码清单 12-1 HTTPRequestHandler * * @author Norman Maurer */ +//扩展 SimpleChannelInboundHandler 以处理 FullHttpRequest 消息 public class HttpRequestHandler extends SimpleChannelInboundHandler { private final String wsUri; private static final File INDEX; @@ -40,12 +41,15 @@ public HttpRequestHandler(String wsUri) { @Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { + //(1) 如果请求了 WebSocket 协议升级,则增加引用计数(调用 retain()方法),并将它传递给下一 个 ChannelInboundHandler if (wsUri.equalsIgnoreCase(request.getUri())) { ctx.fireChannelRead(request.retain()); } else { + //(2) 处理 100 Continue 请求以符合 HTTP 1.1 规范 if (HttpHeaders.is100ContinueExpected(request)) { send100Continue(ctx); } + //读取 index.html RandomAccessFile file = new RandomAccessFile(INDEX, "r"); HttpResponse response = new DefaultHttpResponse( request.getProtocolVersion(), HttpResponseStatus.OK); @@ -53,21 +57,26 @@ public void channelRead0(ChannelHandlerContext ctx, HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); boolean keepAlive = HttpHeaders.isKeepAlive(request); + //如果请求了keep-alive,则添加所需要的 HTTP 头信息 if (keepAlive) { response.headers().set( HttpHeaders.Names.CONTENT_LENGTH, file.length()); response.headers().set( HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } + //(3) 将 HttpResponse 写到客户端 ctx.write(response); + //(4) 将 index.html 写到客户端 if (ctx.pipeline().get(SslHandler.class) == null) { ctx.write(new DefaultFileRegion( file.getChannel(), 0, file.length())); } else { ctx.write(new ChunkedNioFile(file.getChannel())); } + //(5) 写 LastHttpContent 并冲刷至客户端 ChannelFuture future = ctx.writeAndFlush( LastHttpContent.EMPTY_LAST_CONTENT); + //(6) 如果没有请求keep-alive,则在写操作完成后关闭 Channel if (!keepAlive) { future.addListener(ChannelFutureListener.CLOSE); } diff --git a/chapter12/src/main/java/nia/chapter12/SecureChatServer.java b/chapter12/src/main/java/nia/chapter12/SecureChatServer.java index a7779ede..0cd8f3a7 100644 --- a/chapter12/src/main/java/nia/chapter12/SecureChatServer.java +++ b/chapter12/src/main/java/nia/chapter12/SecureChatServer.java @@ -10,10 +10,11 @@ import java.net.InetSocketAddress; /** - * Listing 12.7 Adding encryption to the ChatServer + * 代码清单 12-7 向 ChatServer 添加加密 * * @author Norman Maurer */ +//SecureChatServer 扩展 ChatServer 以支持加密 public class SecureChatServer extends ChatServer { private final SslContext context; @@ -24,6 +25,7 @@ public SecureChatServer(SslContext context) { @Override protected ChannelInitializer createInitializer( ChannelGroup group) { + //返回之前创建的 SecureChatServerInitializer 以启用加密 return new SecureChatServerInitializer(group, context); } diff --git a/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java b/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java index a4b669ac..f2aeb059 100644 --- a/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java +++ b/chapter12/src/main/java/nia/chapter12/SecureChatServerInitializer.java @@ -8,10 +8,11 @@ import javax.net.ssl.SSLEngine; /** - * Listing 12.6 Adding encryption to the ChannelPipeline + * 代码清单 12-6 为 ChannelPipeline 添加加密 * * @author Norman Maurer */ +//扩展 ChatServerInitializer 以添加加密 public class SecureChatServerInitializer extends ChatServerInitializer { private final SslContext context; @@ -23,9 +24,11 @@ public SecureChatServerInitializer(ChannelGroup group, @Override protected void initChannel(Channel ch) throws Exception { + //调用父类的 initChannel() 方法 super.initChannel(ch); SSLEngine engine = context.newEngine(ch.alloc()); engine.setUseClientMode(false); + //将 SslHandler 添加到 ChannelPipeline 中 ch.pipeline().addFirst(new SslHandler(engine)); } } diff --git a/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java b/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java index e781e9c6..5898c6df 100644 --- a/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java +++ b/chapter12/src/main/java/nia/chapter12/TextWebSocketFrameHandler.java @@ -7,10 +7,11 @@ import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; /** - * Listing 12.2 Handling text frames + * 代码清单 12-2 处理文本帧 * * @author Norman Maurer */ +//扩展 SimpleChannelInboundHandler,并处理 TextWebSocketFrame 消息 public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler { private final ChannelGroup group; @@ -19,14 +20,18 @@ public TextWebSocketFrameHandler(ChannelGroup group) { this.group = group; } + //重写 userEventTriggered()方法以处理自定义事件 @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + //如果该事件表示握手成功,则从该 ChannelPipeline 中移除HttpRequest-Handler,因为将不会接收到任何HTTP消息了 if (evt == WebSocketServerProtocolHandler .ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { ctx.pipeline().remove(HttpRequestHandler.class); + //(1) 通知所有已经连接的 WebSocket 客户端新的客户端已经连接上了 group.writeAndFlush(new TextWebSocketFrame( "Client " + ctx.channel() + " joined")); + //(2) 将新的 WebSocket Channel 添加到 ChannelGroup 中,以便它可以接收到所有的消息 group.add(ctx.channel()); } else { super.userEventTriggered(ctx, evt); @@ -36,6 +41,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, @Override public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { + //(3) 增加消息的引用计数,并将它写到 ChannelGroup 中所有已经连接的客户端 group.writeAndFlush(msg.retain()); } } diff --git a/chapter12/src/main/java/nia/chapter12/package-info.java b/chapter12/src/main/java/nia/chapter12/package-info.java index 439b8f09..dae65b22 100644 --- a/chapter12/src/main/java/nia/chapter12/package-info.java +++ b/chapter12/src/main/java/nia/chapter12/package-info.java @@ -2,16 +2,16 @@ * Created by kerr. * * - * Listing 12.1 HTTPRequestHandler {@link nia.chapter12.HttpRequestHandler} + * 代码清单 12-1 HTTPRequestHandler {@link nia.chapter12.HttpRequestHandler} * - * Listing 12.2 Handling text frames {@link nia.chapter12.TextWebSocketFrameHandler} + * 代码清单 12-2 处理文本帧 {@link nia.chapter12.TextWebSocketFrameHandler} * - * Listing 12.3 Initializing the ChannelPipeline {@link nia.chapter12.ChatServerInitializer} + * 代码清单 12-3 初始化 ChannelPipeline {@link nia.chapter12.ChatServerInitializer} * - * Listing 12.4 Bootstrapping the server {@link nia.chapter12.ChatServer} + * 代码清单 12-4 引导服务器 {@link nia.chapter12.ChatServer} * - * Listing 12.6 Adding encryption to the ChannelPipeline {@link nia.chapter12.SecureChatServerInitializer} + * 代码清单 12-6 为 ChannelPipeline 添加加密 {@link nia.chapter12.SecureChatServerInitializer} * - * Listing 12.7 Adding encryption to the ChatServer {@link nia.chapter12.SecureChatServer} + * 代码清单 12-7 向 ChatServer 添加加密 {@link nia.chapter12.SecureChatServer} */ package nia.chapter12; \ No newline at end of file From 4772fe3141b323569d45225c60d5da7e9b2e6be9 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 04:22:00 +0800 Subject: [PATCH 13/75] =?UTF-8?q?+=20=E7=AC=AC13=E7=AB=A0=E7=9A=84?= =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter13/src/main/java/nia/chapter13/LogEvent.java | 8 +++++++- .../main/java/nia/chapter13/LogEventBroadcaster.java | 12 +++++++++++- .../src/main/java/nia/chapter13/LogEventDecoder.java | 7 ++++++- .../src/main/java/nia/chapter13/LogEventEncoder.java | 7 ++++++- .../src/main/java/nia/chapter13/LogEventHandler.java | 6 +++++- .../src/main/java/nia/chapter13/LogEventMonitor.java | 7 ++++++- .../src/main/java/nia/chapter13/package-info.java | 12 ++++++------ 7 files changed, 47 insertions(+), 12 deletions(-) diff --git a/chapter13/src/main/java/nia/chapter13/LogEvent.java b/chapter13/src/main/java/nia/chapter13/LogEvent.java index 6b375d36..197a4bc5 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEvent.java +++ b/chapter13/src/main/java/nia/chapter13/LogEvent.java @@ -3,7 +3,7 @@ import java.net.InetSocketAddress; /** - * Listing 13.1 LogEvent message + * 代码清单 13-1 LogEvent 消息 * * @author Norman Maurer */ @@ -14,10 +14,12 @@ public final class LogEvent { private final String msg; private final long received; + //用于传出消息的构造函数 public LogEvent(String logfile, String msg) { this(null, -1, logfile, msg); } + //用于传入消息的构造函数 public LogEvent(InetSocketAddress source, long received, String logfile, String msg) { this.source = source; @@ -26,18 +28,22 @@ public LogEvent(InetSocketAddress source, long received, this.received = received; } + //返回发送 LogEvent 的源的 InetSocketAddress public InetSocketAddress getSource() { return source; } + //返回所发送的 LogEvent 的日志文件的名称 public String getLogfile() { return logfile; } + //返回消息内容 public String getMsg() { return msg; } + //返回接收 LogEvent 的时间 public long getReceivedTimestamp() { return received; } diff --git a/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java b/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java index 8ba1a017..76cb8501 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventBroadcaster.java @@ -12,7 +12,7 @@ import java.net.InetSocketAddress; /** - * Listing 13.3 LogEventBroadcaster + * 代码清单 13-3 LogEventBroadcaster * * @author Norman Maurer */ @@ -24,33 +24,42 @@ public class LogEventBroadcaster { public LogEventBroadcaster(InetSocketAddress address, File file) { group = new NioEventLoopGroup(); bootstrap = new Bootstrap(); + //引导该 NioDatagramChannel(无连接的) bootstrap.group(group).channel(NioDatagramChannel.class) + //设置 SO_BROADCAST 套接字选项 .option(ChannelOption.SO_BROADCAST, true) .handler(new LogEventEncoder(address)); this.file = file; } public void run() throws Exception { + //绑定 Channel Channel ch = bootstrap.bind(0).sync().channel(); long pointer = 0; + //启动主处理循环 for (;;) { long len = file.length(); if (len < pointer) { // file was reset + //如果有必要,将文件指针设置到该文件的最后一个字节 pointer = len; } else if (len > pointer) { // Content was added RandomAccessFile raf = new RandomAccessFile(file, "r"); + //设置当前的文件指针,以确保没有任何的旧日志被发送 raf.seek(pointer); String line; while ((line = raf.readLine()) != null) { + //对于每个日志条目,写入一个 LogEvent 到 Channel 中 ch.writeAndFlush(new LogEvent(null, -1, file.getAbsolutePath(), line)); } + //存储其在文件中的当前位置 pointer = raf.getFilePointer(); raf.close(); } try { + //休眠 1 秒,如果被中断,则退出循环;否则重新处理它 Thread.sleep(1000); } catch (InterruptedException e) { Thread.interrupted(); @@ -67,6 +76,7 @@ public static void main(String[] args) throws Exception { if (args.length != 2) { throw new IllegalArgumentException(); } + //创建并启动一个新的 LogEventBroadcaster 的实例 LogEventBroadcaster broadcaster = new LogEventBroadcaster( new InetSocketAddress("255.255.255.255", Integer.parseInt(args[0])), new File(args[1])); diff --git a/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java b/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java index 7abaaad9..69acab11 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventDecoder.java @@ -9,7 +9,7 @@ import java.util.List; /** - * Listing 13.6 LogEventDecoder + * 代码清单 13-6 LogEventDecoder * * @author Norman Maurer */ @@ -19,13 +19,18 @@ public class LogEventDecoder extends MessageToMessageDecoder { protected void decode(ChannelHandlerContext ctx, DatagramPacket datagramPacket, List out) throws Exception { + //获取对 DatagramPacket 中的数据(ByteBuf)的引用 ByteBuf data = datagramPacket.content(); + //获取该 SEPARATOR 的索引 int idx = data.indexOf(0, data.readableBytes(), LogEvent.SEPARATOR); + //提取文件名 String filename = data.slice(0, idx) .toString(CharsetUtil.UTF_8); + //提取日志消息 String logMsg = data.slice(idx + 1, data.readableBytes()).toString(CharsetUtil.UTF_8); + //构建一个新的 LogEvent 对象,并且将它添加到(已经解码的消息的)列表中 LogEvent event = new LogEvent(datagramPacket.sender(), System.currentTimeMillis(), filename, logMsg); out.add(event); diff --git a/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java b/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java index ef02bb5c..71667c10 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventEncoder.java @@ -10,13 +10,14 @@ import java.util.List; /** - * Listing 13.2 LogEventEncoder + * 代码清单 13-2 LogEventEncoder * * @author Norman Maurer */ public class LogEventEncoder extends MessageToMessageEncoder { private final InetSocketAddress remoteAddress; + //LogEventEncoder 创建了即将被发送到指定的 InetSocketAddress 的 DatagramPacket 消息 public LogEventEncoder(InetSocketAddress remoteAddress) { this.remoteAddress = remoteAddress; } @@ -28,9 +29,13 @@ protected void encode(ChannelHandlerContext channelHandlerContext, byte[] msg = logEvent.getMsg().getBytes(CharsetUtil.UTF_8); ByteBuf buf = channelHandlerContext.alloc() .buffer(file.length + msg.length + 1); + //将文件名写入到 ByteBuf 中 buf.writeBytes(file); + //添加一个 SEPARATOR buf.writeByte(LogEvent.SEPARATOR); + //将日志消息写入 ByteBuf 中 buf.writeBytes(msg); + //将一个拥有数据和目的地地址的新 DatagramPacket 添加到出站的消息列表中 out.add(new DatagramPacket(buf, remoteAddress)); } } diff --git a/chapter13/src/main/java/nia/chapter13/LogEventHandler.java b/chapter13/src/main/java/nia/chapter13/LogEventHandler.java index cd447d82..474824e4 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventHandler.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventHandler.java @@ -4,16 +4,18 @@ import io.netty.channel.SimpleChannelInboundHandler; /** - * Listing 13.7 LogEventHandler + * 代码清单 13-7 LogEventHandler * * @author Norman Maurer */ +//扩展 SimpleChannelInboundHandler 以处理 LogEvent 消息 public class LogEventHandler extends SimpleChannelInboundHandler { @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + //当异常发生时,打印栈跟踪信息,并关闭对应的 Channel cause.printStackTrace(); ctx.close(); } @@ -21,6 +23,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, @Override public void channelRead0(ChannelHandlerContext ctx, LogEvent event) throws Exception { + //创建 StringBuilder,并且构建输出的字符串 StringBuilder builder = new StringBuilder(); builder.append(event.getReceivedTimestamp()); builder.append(" ["); @@ -29,6 +32,7 @@ public void channelRead0(ChannelHandlerContext ctx, builder.append(event.getLogfile()); builder.append("] : "); builder.append(event.getMsg()); + //打印 LogEvent 的数据 System.out.println(builder.toString()); } } diff --git a/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java b/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java index 76ea2b5b..fff87719 100644 --- a/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java +++ b/chapter13/src/main/java/nia/chapter13/LogEventMonitor.java @@ -8,7 +8,7 @@ import java.net.InetSocketAddress; /** - * Listing 13.8 LogEventMonitor + * 代码清单 13-8 LogEventMonitor * * @author Norman Maurer */ @@ -19,14 +19,17 @@ public class LogEventMonitor { public LogEventMonitor(InetSocketAddress address) { group = new NioEventLoopGroup(); bootstrap = new Bootstrap(); + //引导该 NioDatagramChannel bootstrap.group(group) .channel(NioDatagramChannel.class) + //设置套接字选项 SO_BROADCAST .option(ChannelOption.SO_BROADCAST, true) .handler( new ChannelInitializer() { @Override protected void initChannel(Channel channel) throws Exception { ChannelPipeline pipeline = channel.pipeline(); + //将 LogEventDecoder 和 LogEventHandler 添加到 ChannelPipeline 中 pipeline.addLast(new LogEventDecoder()); pipeline.addLast(new LogEventHandler()); } @@ -35,6 +38,7 @@ protected void initChannel(Channel channel) } public Channel bind() { + //绑定 Channel。注意,DatagramChannel 是无连接的 return bootstrap.bind().syncUninterruptibly().channel(); } @@ -47,6 +51,7 @@ public static void main(String[] args) throws Exception { throw new IllegalArgumentException( "Usage: LogEventMonitor "); } + //构造一个新的 LogEventMonitor LogEventMonitor monitor = new LogEventMonitor( new InetSocketAddress(Integer.parseInt(args[0]))); try { diff --git a/chapter13/src/main/java/nia/chapter13/package-info.java b/chapter13/src/main/java/nia/chapter13/package-info.java index 714ce19c..c36add14 100644 --- a/chapter13/src/main/java/nia/chapter13/package-info.java +++ b/chapter13/src/main/java/nia/chapter13/package-info.java @@ -1,16 +1,16 @@ /** * Created by kerr. * - * Listing 13.1 LogEvent message {@link nia.chapter13.LogEvent} + * 代码清单 13-1 LogEvent 消息 {@link nia.chapter13.LogEvent} * - * Listing 13.2 LogEventEncoder {@link nia.chapter13.LogEventEncoder} + * 代码清单 13-2 LogEventEncoder {@link nia.chapter13.LogEventEncoder} * - * Listing 13.3 LogEventBroadcaster {@link nia.chapter13.LogEventBroadcaster} + * 代码清单 13-3 LogEventBroadcaster {@link nia.chapter13.LogEventBroadcaster} * - * Listing 13.6 LogEventDecoder {@link nia.chapter13.LogEventDecoder} + * 代码清单 13-6 LogEventDecoder {@link nia.chapter13.LogEventDecoder} * - * Listing 13.7 LogEventHandler {@link nia.chapter13.LogEventHandler} + * 代码清单 13-7 LogEventHandler {@link nia.chapter13.LogEventHandler} * - * Listing 13.8 LogEventMonitor {@link nia.chapter13.LogEventMonitor} + * 代码清单 13-8 LogEventMonitor {@link nia.chapter13.LogEventMonitor} */ package nia.chapter13; \ No newline at end of file From fb295624b2b4a39e9ead4cd4726b13a4fe974a4a Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 04:33:56 +0800 Subject: [PATCH 14/75] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9C=AC=E4=B9=A6?= =?UTF-8?q?=E7=9A=84=E5=86=85=E5=AE=B9=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6cf98462..a6432390 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,45 @@ -This Repository contains the source-code for all chapters of the book [Netty in Action](http://manning.com/maurer) -by Norman Maurer and Marvin Allen Wolfthal. +# <> -Latest version: https://github.com/normanmaurer/netty-in-action/tree/2.0-SNAPSHOT +[预售(即将开始)-人民邮电出版社-异步社区](www.epubit.com.cn) -Enjoy! Feedback and PR's welcome! +## 内容提要 +本书是为想要或者正在使用 Java 从事高性能网络编程的人而写的,循序渐进地介绍了 Netty +各个方面的内容。 + +本书共分为 4 个部分:第一部分详细地介绍 Netty 的相关概念以及核心组件,第二部分介绍 +自定义协议经常用到的编解码器,第三部分介绍 Netty 对于应用层高级协议的支持,会覆盖常见 +的协议及其在实践中的应用,第四部分是几个案例研究。此外,附录部分还会简单地介绍 Maven, +以及如何通过使用 Maven 编译和运行本书中的示例。 + +阅读本书不需要读者精通 Java 网络和并发编程。如果想要更加深入地理解本书背后的理念 +以及 Netty 源码本身,可以系统地学习一下 Java 网络编程、 NIO、并发和异步编程以及相关的 +设计模式。 + +## 说明 + +这个仓库包含了[Netty In Action](www.manning.com/maurer/) 这本书的中文版 [Netty实战](www.epubit.com.cn) 的代码清单. +为了更好地服务于读者,进行了如下方面的改进. + + +相对于英文版本(master分支): + +1. 更新了行文中的注释 +2. 按照中文版本的排版进行了调整 +3. 所有的代码清单以及跳转都使用了中文版书籍中的翻译 + + +## 反馈 + +上游版本的更新,请直接将PR的目标调整为本仓库的`master`分支 + +中文版本的更新,请将PR的目标调整为本仓库的`ChineseVersion`分支 + +## 使用 + +请直接克隆本项目即可,建议对照原文查看代码. + +----- Prerequisites From db92e9b0e9caf665db911c69c4947235dcf36658 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 04:39:51 +0800 Subject: [PATCH 15/75] =?UTF-8?q?+=20=E6=B7=BB=E5=8A=A0=E5=B0=81=E9=9D=A2?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a6432390..ef44ed9b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ [预售(即将开始)-人民邮电出版社-异步社区](www.epubit.com.cn) +![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) + + ## 内容提要 本书是为想要或者正在使用 Java 从事高性能网络编程的人而写的,循序渐进地介绍了 Netty From 793a3a45d3a95e095f6bd953fac53db6ea5ae95a Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 04:40:46 +0800 Subject: [PATCH 16/75] =?UTF-8?q?!=20=E6=9B=B4=E6=96=B0=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ef44ed9b..2a76e7df 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,8 @@ Prerequisites - JDK 1.7.0u71 or better - - Maven 3.2.3 or better + maven 3.3.9 + JDK 8 If you want to build everything at once, from the top directory run From c743b83a4881606feb465ccbe288ce7c281a4677 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 04:43:44 +0800 Subject: [PATCH 17/75] = fix url --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2a76e7df..12ba555e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # <> -[预售(即将开始)-人民邮电出版社-异步社区](www.epubit.com.cn) +[预售(即将开始4月下旬)-人民邮电出版社-异步社区](http://www.epubit.com.cn) ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) @@ -21,7 +21,7 @@ ## 说明 -这个仓库包含了[Netty In Action](www.manning.com/maurer/) 这本书的中文版 [Netty实战](www.epubit.com.cn) 的代码清单. +这个仓库包含了[Netty In Action](http://www.manning.com/maurer/) 这本书的中文版 [Netty实战](http://www.epubit.com.cn) 的代码清单. 为了更好地服务于读者,进行了如下方面的改进. From e5d0fd39ffdf70d4b3db3d619060ef35380564ab Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sat, 22 Apr 2017 05:00:12 +0800 Subject: [PATCH 18/75] =?UTF-8?q?=3D=20=E4=BF=AE=E5=A4=8D=E5=AF=B9?= =?UTF-8?q?=E5=88=86=E6=94=AF=E7=9A=84=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12ba555e..0bf4ecb8 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ 为了更好地服务于读者,进行了如下方面的改进. -相对于英文版本(master分支): +相对于英文版本([2.0-SNAPSHOT](https://github.com/ReactivePlatform/netty-in-action-cn/tree/2.0-SNAPSHOT)分支): 1. 更新了行文中的注释 2. 按照中文版本的排版进行了调整 From bfe5b750f20e2b1a81f4f4a6e8fe555cadef08c5 Mon Sep 17 00:00:00 2001 From: kerr Date: Sun, 30 Apr 2017 04:48:50 +0800 Subject: [PATCH 19/75] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加链接 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0bf4ecb8..cd68ab6a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# <> +#《Netty 实战》 Netty In Action 中文版 -[预售(即将开始4月下旬)-人民邮电出版社-异步社区](http://www.epubit.com.cn) +[预售-人民邮电出版社-异步社区](www.epubit.com.cn/book/details/4228) +[预售-京东](https://item.jd.com/12070975.html) ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From 92df3fdc36d6bd593f10f406984e5fb634dee558 Mon Sep 17 00:00:00 2001 From: kerr Date: Sun, 30 Apr 2017 04:49:32 +0800 Subject: [PATCH 20/75] Update README.md fixup --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd68ab6a..01e4208e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -#《Netty 实战》 Netty In Action 中文版 +# 《Netty 实战》 Netty In Action 中文版 [预售-人民邮电出版社-异步社区](www.epubit.com.cn/book/details/4228) + [预售-京东](https://item.jd.com/12070975.html) ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From 46703ecb5e885eef200a8cd1b073383c195aa56a Mon Sep 17 00:00:00 2001 From: kerr Date: Sun, 30 Apr 2017 04:51:28 +0800 Subject: [PATCH 21/75] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01e4208e..30dc776c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 《Netty 实战》 Netty In Action 中文版 -[预售-人民邮电出版社-异步社区](www.epubit.com.cn/book/details/4228) +[预售-人民邮电出版社-异步社区](http://www.epubit.com.cn/book/details/4228) [预售-京东](https://item.jd.com/12070975.html) From 8799c265f4566e69442a6d246795d45626c29fbd Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Wed, 3 May 2017 12:43:31 +0800 Subject: [PATCH 22/75] ! pom upgrade to 4.1.10 --- README.md | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 30dc776c..f2f98597 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # 《Netty 实战》 Netty In Action 中文版 -[预售-人民邮电出版社-异步社区](http://www.epubit.com.cn/book/details/4228) - [预售-京东](https://item.jd.com/12070975.html) +[预售-人民邮电出版社-异步社区](http://www.epubit.com.cn/book/details/4228) + ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) diff --git a/pom.xml b/pom.xml index 578f749f..7e786178 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.9.Final + 4.1.10.Final UTF-8 UTF-8 From 266e315ebcc14e32ead5da5c1a9485c73f43626a Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Wed, 3 May 2017 15:09:35 +0800 Subject: [PATCH 23/75] =?UTF-8?q?remove=20=E5=BC=82=E6=AD=A5=E7=A4=BE?= =?UTF-8?q?=E5=8C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index f2f98597..1fc6a948 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [预售-京东](https://item.jd.com/12070975.html) -[预售-人民邮电出版社-异步社区](http://www.epubit.com.cn/book/details/4228) - ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From 6dcee727e6e077d63add8ee6f33ef73e60c61aff Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Wed, 3 May 2017 16:14:59 +0800 Subject: [PATCH 24/75] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8B=98=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1fc6a948..a5b1b089 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,9 @@ 请直接克隆本项目即可,建议对照原文查看代码. +## 勘误 +[前言: 2001 => 2011](https://github.com/ReactivePlatform/netty-in-action-cn/issues/2) + ----- Prerequisites From 3e31e1b21ea7dc20e1f1745cb6a5b1e496370ff5 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Wed, 3 May 2017 23:03:02 +0800 Subject: [PATCH 25/75] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a5b1b089..c56ce408 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 《Netty 实战》 Netty In Action 中文版 -[预售-京东](https://item.jd.com/12070975.html) +[京东预售链接(优先发货):《Netty实战》([美]诺曼·毛瑞尔(Norman Maurer),马文·艾伦·沃尔夫泰尔(Marvin Allen Wolfthal)) ](https://union-click.jd.com/jdc?d=oN4CCW&come=appmessage) ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From 9558380bc475e9de0fb0d4d39af0cadd776faed1 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Thu, 11 May 2017 19:36:53 +0800 Subject: [PATCH 26/75] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c56ce408..6800cff6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # 《Netty 实战》 Netty In Action 中文版 -[京东预售链接(优先发货):《Netty实战》([美]诺曼·毛瑞尔(Norman Maurer),马文·艾伦·沃尔夫泰尔(Marvin Allen Wolfthal)) ](https://union-click.jd.com/jdc?d=oN4CCW&come=appmessage) +>代码清单已经更新到 Netty 4.1.10.final + +[京东链接(现货发售):《Netty实战》([美]诺曼·毛瑞尔(Norman Maurer),马文·艾伦·沃尔夫泰尔(Marvin Allen Wolfthal)) ](https://union-click.jd.com/jdc?d=oN4CCW&come=appmessage) ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From e274870e4ed4c134773f8daeac4e6a26710faa3e Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Thu, 11 May 2017 23:57:39 +0800 Subject: [PATCH 27/75] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E5=BF=83=E5=BE=97=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 6800cff6..699ff496 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ >代码清单已经更新到 Netty 4.1.10.final +[不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记](http://www.epubit.com.cn/article/1171) + +[不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记(ATA内网)](https://www.atatech.org/articles/79051?flag_data_from=recommend) + [京东链接(现货发售):《Netty实战》([美]诺曼·毛瑞尔(Norman Maurer),马文·艾伦·沃尔夫泰尔(Marvin Allen Wolfthal)) ](https://union-click.jd.com/jdc?d=oN4CCW&come=appmessage) ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From 8d75bad812dc4d185079226026116037a1fc0d33 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Fri, 12 May 2017 23:06:19 +0800 Subject: [PATCH 28/75] ! pom update to 4.1.11 --- README.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 699ff496..b309c325 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 《Netty 实战》 Netty In Action 中文版 ->代码清单已经更新到 Netty 4.1.10.final +>代码清单已经更新到 Netty 4.1.11.final [不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记](http://www.epubit.com.cn/article/1171) diff --git a/pom.xml b/pom.xml index 7e786178..7c2915cc 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.10.Final + 4.1.11.Final UTF-8 UTF-8 From 393320fb3b8845692cfd92cc0b61cd5f53365aba Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Sun, 14 May 2017 21:47:33 +0800 Subject: [PATCH 29/75] =?UTF-8?q?add=20=E7=AD=BE=E5=94=AE=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b309c325..cbd24c3f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ >代码清单已经更新到 Netty 4.1.11.final +[本书在进行限量签售](https://github.com/ReactivePlatform/netty-in-action-cn/issues/3) + [不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记](http://www.epubit.com.cn/article/1171) [不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记(ATA内网)](https://www.atatech.org/articles/79051?flag_data_from=recommend) From fb47d5a7ede5708040de6c3dc83097b3f67ab28c Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Wed, 17 May 2017 21:28:59 +0800 Subject: [PATCH 30/75] =?UTF-8?q?remove=20=E7=AD=BE=E5=94=AE=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cbd24c3f..3eae854b 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,16 @@ >代码清单已经更新到 Netty 4.1.11.final -[本书在进行限量签售](https://github.com/ReactivePlatform/netty-in-action-cn/issues/3) +[如何评价这本书-知乎](https://www.zhihu.com/question/58838575) + +[关于本书-豆瓣](https://book.douban.com/subject/27038538/) + +[京东链接(现货发售):《Netty实战》([美]诺曼·毛瑞尔(Norman Maurer),马文·艾伦·沃尔夫泰尔(Marvin Allen Wolfthal)) ](https://union-click.jd.com/jdc?d=oN4CCW&come=appmessage) [不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记](http://www.epubit.com.cn/article/1171) [不负好时光《Netty IN ACTION》中文版《Netty实战》翻译手记(ATA内网)](https://www.atatech.org/articles/79051?flag_data_from=recommend) -[京东链接(现货发售):《Netty实战》([美]诺曼·毛瑞尔(Norman Maurer),马文·艾伦·沃尔夫泰尔(Marvin Allen Wolfthal)) ](https://union-click.jd.com/jdc?d=oN4CCW&come=appmessage) - ![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) From 76791c442d1b33c2fe85535302406dbddcfec532 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Tue, 23 May 2017 20:58:21 +0800 Subject: [PATCH 31/75] change to html --- chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java b/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java index 2ee0b391..fd9adab5 100644 --- a/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java +++ b/chapter12/src/main/java/nia/chapter12/HttpRequestHandler.java @@ -55,7 +55,7 @@ public void channelRead0(ChannelHandlerContext ctx, request.getProtocolVersion(), HttpResponseStatus.OK); response.headers().set( HttpHeaders.Names.CONTENT_TYPE, - "text/plain; charset=UTF-8"); + "text/html; charset=UTF-8"); boolean keepAlive = HttpHeaders.isKeepAlive(request); //如果请求了keep-alive,则添加所需要的 HTTP 头信息 if (keepAlive) { From 9530933d58cd4e8274a352b88b0b67cec2366126 Mon Sep 17 00:00:00 2001 From: hepin1989 Date: Thu, 6 Jul 2017 20:43:44 +0800 Subject: [PATCH 32/75] update to 4.1.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7c2915cc..76911a25 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.11.Final + 4.1.12.Final UTF-8 UTF-8 From c0f97ab7b1da1282772be033402ed2cbacbb70df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=99=8E=E9=B8=A3?= Date: Mon, 7 Aug 2017 10:14:41 +0800 Subject: [PATCH 33/75] update to 4.1.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 76911a25..e85435f0 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.12.Final + 4.1.14.Final UTF-8 UTF-8 From 8721e55f21fdc3140254a33aac9cd53b68f5d15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=99=8E=E9=B8=A3?= Date: Sat, 26 Aug 2017 15:41:29 +0800 Subject: [PATCH 34/75] update to 4.1.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e85435f0..4ab1357d 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.14.Final + 4.1.15.Final UTF-8 UTF-8 From 8b01b9ea0e421da8ded804ef18d4b4e2c9d527b8 Mon Sep 17 00:00:00 2001 From: "hepin.p" Date: Tue, 7 Nov 2017 14:34:11 +0800 Subject: [PATCH 35/75] ! pom upgrade to netty 4.1.16 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e85435f0..1c0e956a 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.14.Final + 4.1.16.Final UTF-8 UTF-8 From aae4e4412d85095efd7aaedf0ed1c03f983efdf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=99=8E=E9=B8=A3?= Date: Fri, 1 Dec 2017 15:45:39 +0800 Subject: [PATCH 36/75] ! pom upgrade to netty 4.1.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c0e956a..909eb79f 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.16.Final + 4.1.17.Final UTF-8 UTF-8 From a2cb685669bdb089b531846f3fe6da31a838dc18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=99=8E=E9=B8=A3?= Date: Fri, 8 Dec 2017 22:47:19 +0800 Subject: [PATCH 37/75] ! pom update to 4.1.18 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 909eb79f..6819f716 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 4.11 - 4.1.17.Final + 4.1.18.Final UTF-8 UTF-8 From 6edc8d4c01d95f422fe2f3f07a1a1add818f5d7c Mon Sep 17 00:00:00 2001 From: Jary Date: Wed, 13 Dec 2017 13:38:27 +0800 Subject: [PATCH 38/75] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86jquery?= =?UTF-8?q?=E6=BA=90=E6=9D=A5=E8=87=AA=E5=9B=BD=E5=86=85=E7=9A=84=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E7=94=A8=E7=BF=BB=E5=A2=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chapter12/src/main/resources/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter12/src/main/resources/index.html b/chapter12/src/main/resources/index.html index 65ad646b..805764a3 100644 --- a/chapter12/src/main/resources/index.html +++ b/chapter12/src/main/resources/index.html @@ -16,7 +16,7 @@ height: 15em; } - +