From 6c0e800b671ab3c610c5cc280094084aab2b10bd Mon Sep 17 00:00:00 2001 From: telltao Date: Thu, 9 May 2019 16:39:55 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AB=A0=E8=8A=82?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=86=85=E5=AE=B9,=E6=89=8B=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mytest/IntegerToStringDecoderTest.java | 27 +++++++++++++++++ .../mytest/ShortToByteEncodingTest.java | 20 +++++++++++++ .../mytest/ToIntegerDecoderTest.java | 30 +++++++++++++++++++ .../mytest/ToIntegerDecoderTest2.java | 27 +++++++++++++++++ .../main/java/nia/chapter6/WriteHandler.java | 2 ++ .../java/nia/chapter7/ScheduleExamples.java | 10 +++++++ 6 files changed, 116 insertions(+) create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java diff --git a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java new file mode 100644 index 00000000..02a8604d --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java @@ -0,0 +1,27 @@ +package nia.chapter10.mytest; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; + +import java.util.List; + +/** + * Create By LiuTao
+ * 提供一个int 转换为String类型的编码解析器 + * /TODO 如果想看更复杂的例子,请看HttpObjectAggregator + * + * @Date 2019/5/9 15:55 + */ +public class IntegerToStringDecoderTest extends MessageToMessageDecoder { + + + @Override + protected void decode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { + out.add(String.valueOf(msg)); + } +} + + + + + diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java new file mode 100644 index 00000000..7f60ab0c --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java @@ -0,0 +1,20 @@ +package nia.chapter10.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; + +/** + * Create By LiuTao
+ * 将编码转换为解码并发送 + * 如果向实现自己的编码器,请看 WebSocket08FrameEncoder + * @Date 2019/5/9 16:36 + */ +public class ShortToByteEncodingTest extends MessageToByteEncoder { + + @Override + protected void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out) throws Exception { + out.writeShort(msg); + } +} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java new file mode 100644 index 00000000..3396f4c4 --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java @@ -0,0 +1,30 @@ +package nia.chapter10.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +/** + * Create By LiuTao
+ * 扩展 ByteToMessageDecoder类,以将字节解码为特定的格式 + * @Date 2019/5/9 15:07 + */ +public class ToIntegerDecoderTest extends ByteToMessageDecoder { + + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + + if (in.readableBytes() >= 4) { + //从入站ByeBuf中读取一个int,并将其添加到解码消息的List中 + out.add(in.readerIndex()); + } + + + + } + + +} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java new file mode 100644 index 00000000..b9817fff --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java @@ -0,0 +1,27 @@ +package nia.chapter10.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ReplayingDecoder; + +import java.util.List; + +/** + * Create By LiuTao
+ * 扩展ReplayingDecoder 将字节解码为消息 + * ReplayingDecoder 稍慢于 ByteToMessageDecoder + * @Date 2019/5/9 15:16 + */ +public class ToIntegerDecoderTest2 extends ReplayingDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + //此处无需判断是否有数据,因为ReplayingDecoder内部实现已经帮你完成了,因为它内部扩展了 ByteToMessageDecoder + //如果没有足够的字节可用 + out.add(in.readerIndex()); + + + + + } +} diff --git a/chapter6/src/main/java/nia/chapter6/WriteHandler.java b/chapter6/src/main/java/nia/chapter6/WriteHandler.java index f853b16b..0bf89fdb 100644 --- a/chapter6/src/main/java/nia/chapter6/WriteHandler.java +++ b/chapter6/src/main/java/nia/chapter6/WriteHandler.java @@ -13,9 +13,11 @@ 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/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java b/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java index 84147ec0..313101b0 100644 --- a/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java +++ b/chapter7/src/main/java/nia/chapter7/ScheduleExamples.java @@ -1,6 +1,7 @@ package nia.chapter7; import io.netty.channel.Channel; +import io.netty.channel.EventLoop; import io.netty.channel.socket.nio.NioSocketChannel; import java.util.concurrent.Executors; @@ -52,6 +53,12 @@ public void run() { System.out.println("60 seconds later"); } }, 60, TimeUnit.SECONDS); + + + EventLoop loop ; + + + } /** @@ -84,4 +91,7 @@ public void run() { boolean mayInterruptIfRunning = false; future.cancel(mayInterruptIfRunning); } + + + } From 0a6dfaee60b7901f699a9b4ec5a50869c07e76ff Mon Sep 17 00:00:00 2001 From: telltao Date: Fri, 10 May 2019 15:23:35 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A010=E7=AB=A0=E8=8A=82?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=86=85=E5=AE=B9,=E6=89=8B=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mytest/IntegerToStringEncoderTest.java | 24 ++++ .../mytest/MessageToMessageCodecTest.java | 43 +++++++ ...gTest.java => ShortToByteEncoderTest.java} | 5 +- .../mytest/WebSocketConvertHandlerTest.java | 114 ++++++++++++++++++ 4 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java rename chapter10/src/main/java/nia/chapter10/mytest/{ShortToByteEncodingTest.java => ShortToByteEncoderTest.java} (72%) create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java diff --git a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java new file mode 100644 index 00000000..bfd0c311 --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java @@ -0,0 +1,24 @@ +package nia.chapter10.mytest; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; + +import java.util.List; + +/** + * Create By LiuTao
+ *

+ * 将数据编码由Integer转换为String类型 + * encoder: 编码器 将应用数据转换为网络格式 + * decoder 解码器 将网络数据转换为应用数据 + * TODO 更多关于MessageToMessageEncoding的专业语法,请查看 ProtobufEncoder + * 它由google的 Protocol Buffers规范所定义 + *

+ * @Date 2019/5/9 16:58 + */ +public class IntegerToStringEncoderTest extends MessageToMessageEncoder { + @Override + protected void encode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { + out.add(String.valueOf(msg)); + } +} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java b/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java new file mode 100644 index 00000000..bffcb05e --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java @@ -0,0 +1,43 @@ +package nia.chapter10.mytest; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; + +import java.util.List; + +/** + * Create By LiuTao
+ * 解码器:decoder 将应用消息转换为网络消息 + * 编码器:encoder 将网络消息转换为应用消息 + * @Date 2019/5/9 17:53 + */ +public class MessageToMessageCodecTest extends MessageToMessageCodec { + + /** + * 消息解码器 将Integer类型转换为String类型的消息 + * 这个方法调用时会被传入 Integer类型的消息,它将吧他们解码为String类型的消息, + * 消息会被转发给Channelpipeline中的下一个ChannleInboundHandler + * @param ctx + * @param msg + * @param out + * @throws Exception + */ + @Override + protected void decode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { + + } + + /** + * 消息编码器 将String类型的消息转换为Integer类型 + * 对于每个 String类型的消息,这个方法都会被调用,这些消息将会被编码为Integer类型的消息 + * 然后被转发给ChannelPipeline中的下一个ChannelOutboundHandler + * @param ctx + * @param msg + * @param out + * @throws Exception + */ + @Override + protected void encode(ChannelHandlerContext ctx, String msg, List out) throws Exception { + + } +} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java similarity index 72% rename from chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java rename to chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java index 7f60ab0c..317664b4 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncodingTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java @@ -11,10 +11,13 @@ * 如果向实现自己的编码器,请看 WebSocket08FrameEncoder * @Date 2019/5/9 16:36 */ -public class ShortToByteEncodingTest extends MessageToByteEncoder { +public class ShortToByteEncoderTest extends MessageToByteEncoder { @Override protected void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out) throws Exception { out.writeShort(msg); } + + //TODO 编码器: 将应用数据转换为网络格式 encoding + //TODO 解码器:将网络格式转换为应用数据 decoding } diff --git a/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java b/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java new file mode 100644 index 00000000..a614cabf --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java @@ -0,0 +1,114 @@ +package nia.chapter10.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import io.netty.handler.codec.http.websocketx.*; + +import java.util.List; + +/** + * Create By LiuTao
+ * 创建一个Socket转换工具类 + * @Date 2019/5/10 14:13 + */ +@Sharable +public class WebSocketConvertHandlerTest extends MessageToMessageCodec { + + //编码器 + @Override + protected void encode(ChannelHandlerContext ctx, 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: + new IllegalStateException("不受支持的websock消息" + msg); + } + + } + //解码器 + @Override + protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List out) throws Exception { + + ByteBuf payload = msg.content().duplicate(); + + if(msg instanceof BinaryWebSocketFrame){ + out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.BINARY,payload)); + }else if(msg instanceof CloseWebSocketFrame){ + out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.CLOSE,payload)); + }else if(msg instanceof PingWebSocketFrame){ + out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.PING,payload)); + }else if(msg instanceof PongWebSocketFrame){ + out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.PONG,payload)); + }else if(msg instanceof TextWebSocketFrame){ + out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.TEXT,payload)); + }else if(msg instanceof ContinuationWebSocketFrame){ + out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.CONTINUATION,payload)); + }else{ + new IllegalStateException("不受支持的websock消息" + msg); + } + + + + + + } + + public static final class MyWebSocketFrame{ + + public enum FrameType{ + BINARY, + CLOSE, + PING, + PONG, + TEXT, + CONTINUATION + } + + + private final FrameType type; + private final ByteBuf data; + + public MyWebSocketFrame(FrameType type, ByteBuf data) { + this.type = type; + this.data = data; + } + + public FrameType getType() { + return type; + } + + public ByteBuf getData() { + return data; + } + } + + + +} + + From fe00460f403dfbc6b393744a7cc7f4556482ffef Mon Sep 17 00:00:00 2001 From: telltao Date: Mon, 20 May 2019 09:21:05 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=A1=88=E4=BE=8B=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BC=96=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mytest/ByteToChanDecoderText.java | 26 ++++++++ .../chapter10/mytest/CharToByteEncoder.java | 27 ++++++++ .../mytest/CombinedByteCharCodecTest.java | 17 +++++ .../mytest/IntegerToStringDecoderTest.java | 2 +- .../mytest/IntegerToStringEncoderTest.java | 2 +- .../mytest/MessageToMessageCodecTest.java | 4 +- .../mytest/ShortToByteEncoderTest.java | 2 +- .../mytest/ToIntegerDecoderTest.java | 2 +- .../mytest/ToIntegerDecoderTest2.java | 2 +- .../mytest/WebSocketConvertHandlerTest.java | 5 -- .../nia/chapter11/CmdHandlerInitializer.java | 1 + .../mytest/HttpAggregatorInitializerTest.java | 43 ++++++++++++ .../mytest/HttpCodecInitializerTest.java | 65 +++++++++++++++++++ .../mytest/HttpCompressionInitalizerTest.java | 47 ++++++++++++++ .../mytest/HttpPipelineInitializerTest.java | 40 ++++++++++++ .../mytest/HttpsCodecInitializerTest.java | 45 +++++++++++++ .../mytest/IdStateHandlerInitializerTest.java | 49 ++++++++++++++ .../mytest/SslChannelInitializerTest.java | 35 ++++++++++ 18 files changed, 402 insertions(+), 12 deletions(-) create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java create mode 100644 chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpAggregatorInitializerTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java create mode 100644 chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java b/chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java new file mode 100644 index 00000000..46fbf52e --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java @@ -0,0 +1,26 @@ +package nia.chapter10.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +/** + * Create By LiuTao
+ * 10-8 + * 将字节转换为Character + * @Date 2019/5/10 15:46 + */ +public class ByteToChanDecoderText extends ByteToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + + if(in.readableBytes() >2){ + //这里将会自动装箱为Char类型,类型向上转型为自动装箱 + out.add(in.readChar()); + } + } +} + diff --git a/chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java b/chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java new file mode 100644 index 00000000..881096c1 --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java @@ -0,0 +1,27 @@ +package nia.chapter10.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import io.netty.handler.codec.MessageToMessageEncoder; + +import java.util.List; + +/** + * Create By LiuTao
+ * 创建一个编码器 + * 将Char转换为Byte + * encoder: 编码器 将应用数据转换为网络数据 + * decoder: 解码器 将网络数据转换为应用数据 + * @Date 2019/5/10 15:51 + */ +public class CharToByteEncoder extends MessageToByteEncoder { + + + @Override + protected void encode(ChannelHandlerContext ctx, Character msg, ByteBuf out) throws Exception { + out.writeChar(msg); + } + + +} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java b/chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java new file mode 100644 index 00000000..cbca3c97 --- /dev/null +++ b/chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java @@ -0,0 +1,17 @@ +package nia.chapter10.mytest; + +import io.netty.channel.CombinedChannelDuplexHandler; +import nia.chapter10.ByteToCharDecoder; + +/** + * Create By LiuTao
+ * 10-10 构建一个编解码器 + * @Date 2019/5/10 16:11 + */ +public class CombinedByteCharCodecTest extends CombinedChannelDuplexHandler { + + public CombinedByteCharCodecTest() { + //解码器,编码器 + super(new ByteToCharDecoder(),new CharToByteEncoder()); + } +} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java index 02a8604d..1839d6ad 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java @@ -7,7 +7,7 @@ /** * Create By LiuTao
- * 提供一个int 转换为String类型的编码解析器 + * 10.3 提供一个int 转换为String类型的编码解析器 * /TODO 如果想看更复杂的例子,请看HttpObjectAggregator * * @Date 2019/5/9 15:55 diff --git a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java index bfd0c311..bc17f4e0 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java @@ -7,7 +7,7 @@ /** * Create By LiuTao
- *

+ *

10.6 * 将数据编码由Integer转换为String类型 * encoder: 编码器 将应用数据转换为网络格式 * decoder 解码器 将网络数据转换为应用数据 diff --git a/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java b/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java index bffcb05e..f23f4dc8 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java @@ -7,8 +7,8 @@ /** * Create By LiuTao
- * 解码器:decoder 将应用消息转换为网络消息 - * 编码器:encoder 将网络消息转换为应用消息 + * 编码器:encoder 将应用消息转换为网络消息 + * 解码器:decoder 将网络消息转换为应用消息 * @Date 2019/5/9 17:53 */ public class MessageToMessageCodecTest extends MessageToMessageCodec { diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java index 317664b4..7a2e700e 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java @@ -7,7 +7,7 @@ /** * Create By LiuTao
- * 将编码转换为解码并发送 + * 10.5 将编码转换为解码并发送 * 如果向实现自己的编码器,请看 WebSocket08FrameEncoder * @Date 2019/5/9 16:36 */ diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java index 3396f4c4..4618c712 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java @@ -8,7 +8,7 @@ /** * Create By LiuTao
- * 扩展 ByteToMessageDecoder类,以将字节解码为特定的格式 + * 10.1 扩展 ByteToMessageDecoder类,以将字节解码为特定的格式 * @Date 2019/5/9 15:07 */ public class ToIntegerDecoderTest extends ByteToMessageDecoder { diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java index b9817fff..7bd15982 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java @@ -8,7 +8,7 @@ /** * Create By LiuTao
- * 扩展ReplayingDecoder 将字节解码为消息 + * 10.2 扩展ReplayingDecoder 将字节解码为消息 * ReplayingDecoder 稍慢于 ByteToMessageDecoder * @Date 2019/5/9 15:16 */ diff --git a/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java b/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java index a614cabf..83a1e9f3 100644 --- a/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java +++ b/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java @@ -71,11 +71,6 @@ protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List + * 11-3 自动聚合HTTP的消息片段 + * @Date 2019/5/13 11:15 + */ +public class HttpAggregatorInitializerTest extends ChannelInitializer { + + private final boolean isClient; + + public HttpAggregatorInitializerTest(boolean isClient) { + this.isClient = isClient; + } + + @Override + 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()); + } + + //将最大的消息大小为512kb的HttpObjectAggregator添加到ChannelPipeline中 + pipeline.addLast("aggregator",new HttpObjectAggregator(512 * 1024)); + + } + +} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java new file mode 100644 index 00000000..f0e826bf --- /dev/null +++ b/chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java @@ -0,0 +1,65 @@ +package nia.chapter11.mytest; + +import io.netty.channel.*; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.ssl.SslContext; +import nia.chapter11.WebSocketServerInitializer; + +/** + * Create By LiuTao
+ * 11.2.5 11-6 在服务器端支持WebSocket + * @Date 2019/5/13 14:46 + */ +public class HttpCodecInitializerTest extends ChannelInitializer { + + private final SslContext context; + private final boolean isClient; + + public HttpCodecInitializerTest(SslContext context, boolean isClient) { + this.context = context; + this.isClient = isClient; + } + + @Override + protected void initChannel(Channel ch) throws Exception { + + ch.pipeline().addLast( + new HttpServerCodec(), + //为握手提供聚合的HttpRequest + new HttpObjectAggregator(65536), + //如果被请求的端点是/websocket则处理该握手 + new WebSocketServerProtocolHandler("/websocket"), + new TextFrameHandler(), + new BinaryFrameHandler(), + new ContinuationFrameHandler()); + } + + public static final class TextFrameHandler extends SimpleChannelInboundHandler{ + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { + //处理文本数据 + } + } + + + public static final class BinaryFrameHandler extends SimpleChannelInboundHandler{ + + @Override + protected void channelRead0(ChannelHandlerContext ctx, BinaryFrameHandler msg) throws Exception { + //处理二进制数据 + } + } + + + public static final class ContinuationFrameHandler extends SimpleChannelInboundHandler{ + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ContinuationFrameHandler msg) throws Exception { + //继续处理框架 + } + } +} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java new file mode 100644 index 00000000..758ba7cf --- /dev/null +++ b/chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java @@ -0,0 +1,47 @@ +package nia.chapter11.mytest; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpContentDecompressor; +import io.netty.handler.codec.http.HttpServerCodec; + +/** + * Create By LiuTao
+ * 11-4 自动压缩HTTP消息 + * @Date 2019/5/13 11:27 + */ +public class HttpCompressionInitalizerTest extends ChannelInitializer { + + private final boolean isClient; + + public HttpCompressionInitalizerTest(boolean isClient) { + this.isClient = isClient; + } + + /*** + * 压缩需添加 pom 依赖 + * groupId: com.jcraft + * artifactId: jzlib + * version: 1.1.3 + * */ + + + + @Override + protected void initChannel(Channel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + + if(isClient){ + + pipeline.addLast("codec",new HttpClientCodec()); + //添加 HttpContentDecompressor 以处理来自服务器的压缩内容 + pipeline.addLast("decompressor",new HttpContentDecompressor()); + }else{ + pipeline.addLast("codec",new HttpServerCodec()); + //如果是服务器,则添加 HttpContentDecompressor 来压缩(如果客户端支持它) + pipeline.addLast("compressor",new HttpContentDecompressor()); + } + } +} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java new file mode 100644 index 00000000..fe6ebf93 --- /dev/null +++ b/chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java @@ -0,0 +1,40 @@ +package nia.chapter11.mytest; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.codec.http.HttpResponseDecoder; +import io.netty.handler.codec.http.HttpResponseEncoder; + +/** + * Create By LiuTao
+ * 11-2 添加HTTP支持 + * @Date 2019/5/13 11:01 + */ +public class HttpPipelineInitializerTest extends ChannelInitializer { + + private final boolean client; + + public HttpPipelineInitializerTest(boolean client) { + this.client = client; + } + + @Override + protected void initChannel(Channel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + if(client){ + //如果是客户端,则添加解码器已处理来自服务器的响应 + pipeline.addLast("decoder",new HttpResponseDecoder()); + //添加 编码器 向服务器发送请求 + pipeline.addLast("encoder",new HttpResponseEncoder()); + }else{ + //添加解码器处理来自服务器的数据 + pipeline.addLast("decoder",new HttpRequestDecoder()); + //添加编码器用于向服务器发送数据 + pipeline.addLast("encoder",new HttpResponseEncoder()); + + } + + } +} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java new file mode 100644 index 00000000..3fc728c5 --- /dev/null +++ b/chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java @@ -0,0 +1,45 @@ +package nia.chapter11.mytest; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.http.HttpClientCodec; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslHandler; + +import javax.net.ssl.SSLEngine; + +/** + * Create By LiuTao
+ * 11.2.4 11-5 使用HTTPS + * @Date 2019/5/13 13:48 + */ +public class HttpsCodecInitializerTest extends ChannelInitializer { + + private final SslContext context; + private final boolean isClient; + + public HttpsCodecInitializerTest(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()); + //如果支持HTTPS 则需要把ssl添加到 channelPipeline管道中的第一位 + pipeline.addFirst("ssl",new SslHandler(engine)); + + if(isClient){ + //如果是客户端,则添加客户端的Codec + pipeline.addLast("codec",new HttpClientCodec()); + }else{ + //如果是服务端,则添加服务端的Codec + pipeline.addLast("codec",new HttpServerCodec()); + } + + + } +} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java new file mode 100644 index 00000000..e4754338 --- /dev/null +++ b/chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java @@ -0,0 +1,49 @@ +package nia.chapter11.mytest; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.*; +import io.netty.handler.timeout.IdleStateEvent; +import io.netty.handler.timeout.IdleStateHandler; +import io.netty.util.CharsetUtil; + +import java.util.concurrent.TimeUnit; + +/** + * Create By LiuTao
+ * 11.3 空闲的连接和超时 + * 11-7 发送心跳 + * @Date 2019/5/13 15:20 + */ +public class IdStateHandlerInitializerTest extends ChannelInitializer { + + @Override + protected void initChannel(Channel ch) throws Exception { + ChannelPipeline pipeline = ch.pipeline(); + + pipeline.addLast(new IdleStateHandler(0,0,60,TimeUnit.SECONDS)); + //将一个HeartbeatHandler添加到channelPipeline中 + pipeline.addLast(new HeartbeatHandler()); + } + public static final class HeartbeatHandler extends ChannelInboundHandlerAdapter{ + //发送到远程节点的消息 + private static final ByteBuf HEARTBEAT_SQEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer( + "HEARTBEAT",CharsetUtil.ISO_8859_1)); + + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if(evt instanceof IdleStateEvent){ + //发送心跳消息,如果连接失败,则关闭连接 + ctx.writeAndFlush(HEARTBEAT_SQEQUENCE.duplicate()) + .addListener(ChannelFutureListener.CLOSE_ON_FAILURE); + }else{ + //如果不是IdleStateEvent事件,所以将它传递给下一个ChannelInboundHandler + super.userEventTriggered(ctx,evt); + } + } + } + + + +} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java new file mode 100644 index 00000000..58060669 --- /dev/null +++ b/chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java @@ -0,0 +1,35 @@ +package nia.chapter11.mytest; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslHandler; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +/** + * Create By LiuTao
+ * 11-1 添加SSL支持 + * @Date 2019/5/10 17:38 + */ +public class SslChannelInitializerTest extends ChannelInitializer { + + private final SslContext context; + private final boolean startTls; + + public SslChannelInitializerTest(SslContext context, boolean startTls) { + this.context = context; + //如果设置为true 第一个写入到消息将不会被加密(客户端应该设置为true) + 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)); + + } +} From 9167069f5b8e51bd24b360bc5fb92b41cb730ed0 Mon Sep 17 00:00:00 2001 From: telltao Date: Tue, 13 Apr 2021 21:41:30 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=B0=86=E4=BB=A3=E7=A0=81=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E6=B1=89=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 64 ++++++++-- .../java/nia/chapter1/BlockingIoExample.java | 11 +- .../java/nia/chapter1/ConnectExample.java | 15 ++- .../java/nia/chapter1/ConnectHandler.java | 3 +- .../main/java/nia/chapter1/package-info.java | 8 +- .../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 +- .../mytest/ByteToChanDecoderText.java | 26 ---- .../chapter10/mytest/CharToByteEncoder.java | 27 ----- .../mytest/CombinedByteCharCodecTest.java | 17 --- .../mytest/IntegerToStringDecoderTest.java | 27 ----- .../mytest/IntegerToStringEncoderTest.java | 24 ---- .../mytest/MessageToMessageCodecTest.java | 43 ------- .../mytest/ShortToByteEncoderTest.java | 23 ---- .../mytest/ToIntegerDecoderTest.java | 30 ----- .../mytest/ToIntegerDecoderTest2.java | 27 ----- .../mytest/WebSocketConvertHandlerTest.java | 109 ----------------- .../main/java/nia/chapter10/package-info.java | 20 ++-- chapter11/pom.xml | 2 +- .../ChunkedWriteHandlerInitializer.java | 6 +- .../nia/chapter11/CmdHandlerInitializer.java | 12 +- .../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 +- .../mytest/HttpAggregatorInitializerTest.java | 43 ------- .../mytest/HttpCodecInitializerTest.java | 65 ---------- .../mytest/HttpCompressionInitalizerTest.java | 47 -------- .../mytest/HttpPipelineInitializerTest.java | 40 ------- .../mytest/HttpsCodecInitializerTest.java | 45 ------- .../mytest/IdStateHandlerInitializerTest.java | 49 -------- .../mytest/SslChannelInitializerTest.java | 35 ------ .../main/java/nia/chapter11/package-info.java | 28 ++--- chapter12/pom.xml | 4 +- .../main/java/nia/chapter12/ChatServer.java | 6 +- .../nia/chapter12/ChatServerInitializer.java | 4 +- .../nia/chapter12/HttpRequestHandler.java | 11 +- .../java/nia/chapter12/SecureChatServer.java | 4 +- .../SecureChatServerInitializer.java | 5 +- .../chapter12/TextWebSocketFrameHandler.java | 8 +- .../main/java/nia/chapter12/package-info.java | 12 +- chapter12/src/main/resources/index.html | 2 +- chapter13/pom.xml | 4 +- .../src/main/java/nia/chapter13/LogEvent.java | 8 +- .../nia/chapter13/LogEventBroadcaster.java | 12 +- .../java/nia/chapter13/LogEventDecoder.java | 7 +- .../java/nia/chapter13/LogEventEncoder.java | 7 +- .../java/nia/chapter13/LogEventHandler.java | 6 +- .../java/nia/chapter13/LogEventMonitor.java | 7 +- .../main/java/nia/chapter13/package-info.java | 12 +- .../nia/chapter2/echoclient/EchoClient.java | 10 +- .../echoclient/EchoClientHandler.java | 6 +- .../main/java/nia/chapter2/package-info.java | 4 +- .../nia/chapter2/echoserver/EchoServer.java | 16 ++- .../echoserver/EchoServerHandler.java | 8 +- .../main/java/nia/chapter2/package-info.java | 4 +- .../chapter4/ChannelOperationExamples.java | 17 ++- .../java/nia/chapter4/NettyNioServer.java | 10 +- .../java/nia/chapter4/NettyOioServer.java | 8 ++ .../java/nia/chapter4/PlainNioServer.java | 12 +- .../java/nia/chapter4/PlainOioServer.java | 8 +- .../main/java/nia/chapter4/package-info.java | 12 +- .../channel/DummyChannelHandlerContext.java | 8 +- .../java/nia.chapter5/ByteBufExamples.java | 111 ++++++++++++------ .../main/java/nia.chapter5/package-info.java | 32 ++--- .../channel/DummyChannelHandlerContext.java | 8 +- .../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 | 6 +- .../main/java/nia/chapter6/WriteHandlers.java | 16 ++- .../main/java/nia/chapter6/package-info.java | 28 ++--- .../java/nia/chapter7/EventLoopExamples.java | 6 +- .../java/nia/chapter7/ScheduleExamples.java | 46 ++++---- .../main/java/nia/chapter7/package-info.java | 10 +- .../java/nia/chapter8/BootstrapClient.java | 14 ++- .../BootstrapClientWithOptionsAndAttrs.java | 13 +- .../chapter8/BootstrapDatagramChannel.java | 9 +- .../java/nia/chapter8/BootstrapServer.java | 9 +- .../BootstrapSharingEventLoopGroup.java | 15 ++- .../chapter8/BootstrapWithInitializer.java | 11 +- .../java/nia/chapter8/GracefulShutdown.java | 7 +- .../nia/chapter8/InvalidBootstrapClient.java | 14 ++- .../main/java/nia/chapter8/package-info.java | 16 +-- .../java/nia/chapter9/AbsIntegerEncoder.java | 6 +- .../nia/chapter9/FixedLengthFrameDecoder.java | 7 +- .../java/nia/chapter9/FrameChunkDecoder.java | 7 +- .../main/java/nia/chapter9/package-info.java | 6 +- .../test/chapter9/AbsIntegerEncoderTest.java | 7 +- .../chapter9/FixedLengthFrameDecoderTest.java | 11 +- .../test/chapter9/FrameChunkDecoderTest.java | 10 +- .../java/nia/test/chapter9/package-info.java | 6 +- pom.xml | 16 +-- utils/pom.xml | 2 +- 117 files changed, 730 insertions(+), 975 deletions(-) delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java delete mode 100644 chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpAggregatorInitializerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java delete mode 100644 chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java diff --git a/README.md b/README.md index c134145c..2a7eee0b 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,66 @@ -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. +# 《Netty 实战》 Netty In Action 中文版 -Latest version: https://github.com/normanmaurer/netty-in-action/tree/2.0-SNAPSHOT +>代码清单已经更新到 Netty 4.1.25.final -Enjoy! Feedback and PR's welcome! +[如何评价这本书-知乎](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) + +![image](https://cloud.githubusercontent.com/assets/501740/25295296/94d2ef06-2715-11e7-9a2a-916d77014cfc.png) + + +## 内容提要 + +本书是为想要或者正在使用 Java 从事高性能网络编程的人而写的,循序渐进地介绍了 Netty +各个方面的内容。 + +本书共分为 4 个部分:第一部分详细地介绍 Netty 的相关概念以及核心组件,第二部分介绍 +自定义协议经常用到的编解码器,第三部分介绍 Netty 对于应用层高级协议的支持,会覆盖常见 +的协议及其在实践中的应用,第四部分是几个案例研究。此外,附录部分还会简单地介绍 Maven, +以及如何通过使用 Maven 编译和运行本书中的示例。 + +阅读本书不需要读者精通 Java 网络和并发编程。如果想要更加深入地理解本书背后的理念 +以及 Netty 源码本身,可以系统地学习一下 Java 网络编程、 NIO、并发和异步编程以及相关的 +设计模式。 + +## 说明 + +这个仓库包含了[Netty In Action](http://www.manning.com/maurer/) 这本书的中文版 [Netty实战](http://www.epubit.com.cn) 的代码清单. +为了更好地服务于读者,进行了如下方面的改进. -Prerequisites - JDK 1.7.0u71 or better +相对于英文版本([2.0-SNAPSHOT](https://github.com/ReactivePlatform/netty-in-action-cn/tree/2.0-SNAPSHOT)分支): + +1. 更新了行文中的注释 +2. 按照中文版本的排版进行了调整 +3. 所有的代码清单以及跳转都使用了中文版书籍中的翻译 + + +## 反馈 + +上游版本的更新,请直接将PR的目标调整为本仓库的`master`分支 + +中文版本的更新,请将PR的目标调整为本仓库的`ChineseVersion`分支 + +## 使用 + +请直接克隆本项目即可,建议对照原文查看代码. + +## 勘误 +[前言: 2001 => 2011](https://github.com/ReactivePlatform/netty-in-action-cn/issues/2) + +----- + +Prerequisites - Maven 3.3.9 or better + maven 3.3.9 + JDK 8 If you want to build everything at once, from the top directory run diff --git a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java index 6ac3dc14..bd2d002f 100644 --- a/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java +++ b/chapter1/src/main/java/nia/chapter1/BlockingIoExample.java @@ -10,27 +10,34 @@ /** * 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); + //继续执行处理循环 } } 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 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/mytest/ByteToChanDecoderText.java b/chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java deleted file mode 100644 index 46fbf52e..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/ByteToChanDecoderText.java +++ /dev/null @@ -1,26 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - -import java.util.List; - -/** - * Create By LiuTao
- * 10-8 - * 将字节转换为Character - * @Date 2019/5/10 15:46 - */ -public class ByteToChanDecoderText extends ByteToMessageDecoder { - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - - if(in.readableBytes() >2){ - //这里将会自动装箱为Char类型,类型向上转型为自动装箱 - out.add(in.readChar()); - } - } -} - diff --git a/chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java b/chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java deleted file mode 100644 index 881096c1..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/CharToByteEncoder.java +++ /dev/null @@ -1,27 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; -import io.netty.handler.codec.MessageToMessageEncoder; - -import java.util.List; - -/** - * Create By LiuTao
- * 创建一个编码器 - * 将Char转换为Byte - * encoder: 编码器 将应用数据转换为网络数据 - * decoder: 解码器 将网络数据转换为应用数据 - * @Date 2019/5/10 15:51 - */ -public class CharToByteEncoder extends MessageToByteEncoder { - - - @Override - protected void encode(ChannelHandlerContext ctx, Character msg, ByteBuf out) throws Exception { - out.writeChar(msg); - } - - -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java b/chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java deleted file mode 100644 index cbca3c97..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/CombinedByteCharCodecTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.channel.CombinedChannelDuplexHandler; -import nia.chapter10.ByteToCharDecoder; - -/** - * Create By LiuTao
- * 10-10 构建一个编解码器 - * @Date 2019/5/10 16:11 - */ -public class CombinedByteCharCodecTest extends CombinedChannelDuplexHandler { - - public CombinedByteCharCodecTest() { - //解码器,编码器 - super(new ByteToCharDecoder(),new CharToByteEncoder()); - } -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java deleted file mode 100644 index 1839d6ad..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringDecoderTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageDecoder; - -import java.util.List; - -/** - * Create By LiuTao
- * 10.3 提供一个int 转换为String类型的编码解析器 - * /TODO 如果想看更复杂的例子,请看HttpObjectAggregator - * - * @Date 2019/5/9 15:55 - */ -public class IntegerToStringDecoderTest extends MessageToMessageDecoder { - - - @Override - protected void decode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { - out.add(String.valueOf(msg)); - } -} - - - - - diff --git a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java deleted file mode 100644 index bc17f4e0..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/IntegerToStringEncoderTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageEncoder; - -import java.util.List; - -/** - * Create By LiuTao
- *

10.6 - * 将数据编码由Integer转换为String类型 - * encoder: 编码器 将应用数据转换为网络格式 - * decoder 解码器 将网络数据转换为应用数据 - * TODO 更多关于MessageToMessageEncoding的专业语法,请查看 ProtobufEncoder - * 它由google的 Protocol Buffers规范所定义 - *

- * @Date 2019/5/9 16:58 - */ -public class IntegerToStringEncoderTest extends MessageToMessageEncoder { - @Override - protected void encode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { - out.add(String.valueOf(msg)); - } -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java b/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java deleted file mode 100644 index f23f4dc8..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/MessageToMessageCodecTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageCodec; - -import java.util.List; - -/** - * Create By LiuTao
- * 编码器:encoder 将应用消息转换为网络消息 - * 解码器:decoder 将网络消息转换为应用消息 - * @Date 2019/5/9 17:53 - */ -public class MessageToMessageCodecTest extends MessageToMessageCodec { - - /** - * 消息解码器 将Integer类型转换为String类型的消息 - * 这个方法调用时会被传入 Integer类型的消息,它将吧他们解码为String类型的消息, - * 消息会被转发给Channelpipeline中的下一个ChannleInboundHandler - * @param ctx - * @param msg - * @param out - * @throws Exception - */ - @Override - protected void decode(ChannelHandlerContext ctx, Integer msg, List out) throws Exception { - - } - - /** - * 消息编码器 将String类型的消息转换为Integer类型 - * 对于每个 String类型的消息,这个方法都会被调用,这些消息将会被编码为Integer类型的消息 - * 然后被转发给ChannelPipeline中的下一个ChannelOutboundHandler - * @param ctx - * @param msg - * @param out - * @throws Exception - */ - @Override - protected void encode(ChannelHandlerContext ctx, String msg, List out) throws Exception { - - } -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java deleted file mode 100644 index 7a2e700e..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/ShortToByteEncoderTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; -import io.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; - -/** - * Create By LiuTao
- * 10.5 将编码转换为解码并发送 - * 如果向实现自己的编码器,请看 WebSocket08FrameEncoder - * @Date 2019/5/9 16:36 - */ -public class ShortToByteEncoderTest extends MessageToByteEncoder { - - @Override - protected void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out) throws Exception { - out.writeShort(msg); - } - - //TODO 编码器: 将应用数据转换为网络格式 encoding - //TODO 解码器:将网络格式转换为应用数据 decoding -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java deleted file mode 100644 index 4618c712..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest.java +++ /dev/null @@ -1,30 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - -import java.util.List; - -/** - * Create By LiuTao
- * 10.1 扩展 ByteToMessageDecoder类,以将字节解码为特定的格式 - * @Date 2019/5/9 15:07 - */ -public class ToIntegerDecoderTest extends ByteToMessageDecoder { - - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - - if (in.readableBytes() >= 4) { - //从入站ByeBuf中读取一个int,并将其添加到解码消息的List中 - out.add(in.readerIndex()); - } - - - - } - - -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java b/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java deleted file mode 100644 index 7bd15982..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/ToIntegerDecoderTest2.java +++ /dev/null @@ -1,27 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ReplayingDecoder; - -import java.util.List; - -/** - * Create By LiuTao
- * 10.2 扩展ReplayingDecoder 将字节解码为消息 - * ReplayingDecoder 稍慢于 ByteToMessageDecoder - * @Date 2019/5/9 15:16 - */ -public class ToIntegerDecoderTest2 extends ReplayingDecoder { - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - //此处无需判断是否有数据,因为ReplayingDecoder内部实现已经帮你完成了,因为它内部扩展了 ByteToMessageDecoder - //如果没有足够的字节可用 - out.add(in.readerIndex()); - - - - - } -} diff --git a/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java b/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java deleted file mode 100644 index 83a1e9f3..00000000 --- a/chapter10/src/main/java/nia/chapter10/mytest/WebSocketConvertHandlerTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package nia.chapter10.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandler.Sharable; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageCodec; -import io.netty.handler.codec.http.websocketx.*; - -import java.util.List; - -/** - * Create By LiuTao
- * 创建一个Socket转换工具类 - * @Date 2019/5/10 14:13 - */ -@Sharable -public class WebSocketConvertHandlerTest extends MessageToMessageCodec { - - //编码器 - @Override - protected void encode(ChannelHandlerContext ctx, 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: - new IllegalStateException("不受支持的websock消息" + msg); - } - - } - //解码器 - @Override - protected void decode(ChannelHandlerContext ctx, WebSocketFrame msg, List out) throws Exception { - - ByteBuf payload = msg.content().duplicate(); - - if(msg instanceof BinaryWebSocketFrame){ - out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.BINARY,payload)); - }else if(msg instanceof CloseWebSocketFrame){ - out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.CLOSE,payload)); - }else if(msg instanceof PingWebSocketFrame){ - out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.PING,payload)); - }else if(msg instanceof PongWebSocketFrame){ - out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.PONG,payload)); - }else if(msg instanceof TextWebSocketFrame){ - out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.TEXT,payload)); - }else if(msg instanceof ContinuationWebSocketFrame){ - out.add(new MyWebSocketFrame(MyWebSocketFrame.FrameType.CONTINUATION,payload)); - }else{ - new IllegalStateException("不受支持的websock消息" + msg); - } - } - - public static final class MyWebSocketFrame{ - - public enum FrameType{ - BINARY, - CLOSE, - PING, - PONG, - TEXT, - CONTINUATION - } - - - private final FrameType type; - private final ByteBuf data; - - public MyWebSocketFrame(FrameType type, ByteBuf data) { - this.type = type; - this.data = data; - } - - public FrameType getType() { - return type; - } - - public ByteBuf getData() { - return data; - } - } - - - -} - - 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 diff --git a/chapter11/pom.xml b/chapter11/pom.xml index fd51c61f..162db5e4 100644 --- a/chapter11/pom.xml +++ b/chapter11/pom.xml @@ -12,7 +12,7 @@ chapter11 Chapter 11. Provided ChannelHandlers and codecs - 2.5.0 + 3.9.0 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 a33f6df3..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,13 +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())); } @@ -62,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/mytest/HttpAggregatorInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpAggregatorInitializerTest.java deleted file mode 100644 index 6804fd4c..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/HttpAggregatorInitializerTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpServerCodec; - -import java.util.ArrayList; -import java.util.List; - -/** - * Create By LiuTao
- * 11-3 自动聚合HTTP的消息片段 - * @Date 2019/5/13 11:15 - */ -public class HttpAggregatorInitializerTest extends ChannelInitializer { - - private final boolean isClient; - - public HttpAggregatorInitializerTest(boolean isClient) { - this.isClient = isClient; - } - - @Override - 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()); - } - - //将最大的消息大小为512kb的HttpObjectAggregator添加到ChannelPipeline中 - pipeline.addLast("aggregator",new HttpObjectAggregator(512 * 1024)); - - } - -} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java deleted file mode 100644 index f0e826bf..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/HttpCodecInitializerTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.channel.*; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpServerCodec; -import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; -import io.netty.handler.ssl.SslContext; -import nia.chapter11.WebSocketServerInitializer; - -/** - * Create By LiuTao
- * 11.2.5 11-6 在服务器端支持WebSocket - * @Date 2019/5/13 14:46 - */ -public class HttpCodecInitializerTest extends ChannelInitializer { - - private final SslContext context; - private final boolean isClient; - - public HttpCodecInitializerTest(SslContext context, boolean isClient) { - this.context = context; - this.isClient = isClient; - } - - @Override - protected void initChannel(Channel ch) throws Exception { - - ch.pipeline().addLast( - new HttpServerCodec(), - //为握手提供聚合的HttpRequest - new HttpObjectAggregator(65536), - //如果被请求的端点是/websocket则处理该握手 - new WebSocketServerProtocolHandler("/websocket"), - new TextFrameHandler(), - new BinaryFrameHandler(), - new ContinuationFrameHandler()); - } - - public static final class TextFrameHandler extends SimpleChannelInboundHandler{ - - @Override - protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { - //处理文本数据 - } - } - - - public static final class BinaryFrameHandler extends SimpleChannelInboundHandler{ - - @Override - protected void channelRead0(ChannelHandlerContext ctx, BinaryFrameHandler msg) throws Exception { - //处理二进制数据 - } - } - - - public static final class ContinuationFrameHandler extends SimpleChannelInboundHandler{ - - @Override - protected void channelRead0(ChannelHandlerContext ctx, ContinuationFrameHandler msg) throws Exception { - //继续处理框架 - } - } -} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java deleted file mode 100644 index 758ba7cf..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/HttpCompressionInitalizerTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpContentDecompressor; -import io.netty.handler.codec.http.HttpServerCodec; - -/** - * Create By LiuTao
- * 11-4 自动压缩HTTP消息 - * @Date 2019/5/13 11:27 - */ -public class HttpCompressionInitalizerTest extends ChannelInitializer { - - private final boolean isClient; - - public HttpCompressionInitalizerTest(boolean isClient) { - this.isClient = isClient; - } - - /*** - * 压缩需添加 pom 依赖 - * groupId: com.jcraft - * artifactId: jzlib - * version: 1.1.3 - * */ - - - - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - - if(isClient){ - - pipeline.addLast("codec",new HttpClientCodec()); - //添加 HttpContentDecompressor 以处理来自服务器的压缩内容 - pipeline.addLast("decompressor",new HttpContentDecompressor()); - }else{ - pipeline.addLast("codec",new HttpServerCodec()); - //如果是服务器,则添加 HttpContentDecompressor 来压缩(如果客户端支持它) - pipeline.addLast("compressor",new HttpContentDecompressor()); - } - } -} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java deleted file mode 100644 index fe6ebf93..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/HttpPipelineInitializerTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; - -/** - * Create By LiuTao
- * 11-2 添加HTTP支持 - * @Date 2019/5/13 11:01 - */ -public class HttpPipelineInitializerTest extends ChannelInitializer { - - private final boolean client; - - public HttpPipelineInitializerTest(boolean client) { - this.client = client; - } - - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - if(client){ - //如果是客户端,则添加解码器已处理来自服务器的响应 - pipeline.addLast("decoder",new HttpResponseDecoder()); - //添加 编码器 向服务器发送请求 - pipeline.addLast("encoder",new HttpResponseEncoder()); - }else{ - //添加解码器处理来自服务器的数据 - pipeline.addLast("decoder",new HttpRequestDecoder()); - //添加编码器用于向服务器发送数据 - pipeline.addLast("encoder",new HttpResponseEncoder()); - - } - - } -} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java deleted file mode 100644 index 3fc728c5..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/HttpsCodecInitializerTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.http.HttpClientCodec; -import io.netty.handler.codec.http.HttpServerCodec; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslHandler; - -import javax.net.ssl.SSLEngine; - -/** - * Create By LiuTao
- * 11.2.4 11-5 使用HTTPS - * @Date 2019/5/13 13:48 - */ -public class HttpsCodecInitializerTest extends ChannelInitializer { - - private final SslContext context; - private final boolean isClient; - - public HttpsCodecInitializerTest(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()); - //如果支持HTTPS 则需要把ssl添加到 channelPipeline管道中的第一位 - pipeline.addFirst("ssl",new SslHandler(engine)); - - if(isClient){ - //如果是客户端,则添加客户端的Codec - pipeline.addLast("codec",new HttpClientCodec()); - }else{ - //如果是服务端,则添加服务端的Codec - pipeline.addLast("codec",new HttpServerCodec()); - } - - - } -} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java deleted file mode 100644 index e4754338..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/IdStateHandlerInitializerTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.*; -import io.netty.handler.timeout.IdleStateEvent; -import io.netty.handler.timeout.IdleStateHandler; -import io.netty.util.CharsetUtil; - -import java.util.concurrent.TimeUnit; - -/** - * Create By LiuTao
- * 11.3 空闲的连接和超时 - * 11-7 发送心跳 - * @Date 2019/5/13 15:20 - */ -public class IdStateHandlerInitializerTest extends ChannelInitializer { - - @Override - protected void initChannel(Channel ch) throws Exception { - ChannelPipeline pipeline = ch.pipeline(); - - pipeline.addLast(new IdleStateHandler(0,0,60,TimeUnit.SECONDS)); - //将一个HeartbeatHandler添加到channelPipeline中 - pipeline.addLast(new HeartbeatHandler()); - } - public static final class HeartbeatHandler extends ChannelInboundHandlerAdapter{ - //发送到远程节点的消息 - private static final ByteBuf HEARTBEAT_SQEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer( - "HEARTBEAT",CharsetUtil.ISO_8859_1)); - - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if(evt instanceof IdleStateEvent){ - //发送心跳消息,如果连接失败,则关闭连接 - ctx.writeAndFlush(HEARTBEAT_SQEQUENCE.duplicate()) - .addListener(ChannelFutureListener.CLOSE_ON_FAILURE); - }else{ - //如果不是IdleStateEvent事件,所以将它传递给下一个ChannelInboundHandler - super.userEventTriggered(ctx,evt); - } - } - } - - - -} diff --git a/chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java b/chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java deleted file mode 100644 index 58060669..00000000 --- a/chapter11/src/main/java/nia/chapter11/mytest/SslChannelInitializerTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package nia.chapter11.mytest; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslHandler; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; - -/** - * Create By LiuTao
- * 11-1 添加SSL支持 - * @Date 2019/5/10 17:38 - */ -public class SslChannelInitializerTest extends ChannelInitializer { - - private final SslContext context; - private final boolean startTls; - - public SslChannelInitializerTest(SslContext context, boolean startTls) { - this.context = context; - //如果设置为true 第一个写入到消息将不会被加密(客户端应该设置为true) - 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/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 diff --git a/chapter12/pom.xml b/chapter12/pom.xml index f22a818c..07be1f93 100644 --- a/chapter12/pom.xml +++ b/chapter12/pom.xml @@ -33,7 +33,7 @@ org.codehaus.mojo exec-maven-plugin - 1.2.1 + 1.6.0 java @@ -58,7 +58,7 @@ org.codehaus.mojo exec-maven-plugin - 1.2.1 + 1.6.0 java 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 cd67de6f..fd9adab5 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/html; 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 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; } - +