情景导入

学习了前面的基础信息,我们发现我们的大部分内容都是基于 Bytebuf 去处理的。

对于 java 这一门 OO 的语言而言,我们更加习惯的是使用 Pojo 去处理。

代码示例

对象定义

  • UnixTime.java
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class UnixTime { private final long value; public UnixTime() { this(System.currentTimeMillis() / 1000L + 2208988800L); } public UnixTime(long value) { this.value = value; } public long value() { return value; } @Override public String toString() { return new Date((value() - 2208988800L) * 1000L).toString(); } }

服务端

  • PojoTimeServer.java
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class PojoTimeServer { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); ChannelFuture channelFuture = serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new TimeEncoder()).addLast(new PojoTimeServerHandler()); } }).bind(8888) .syncUninterruptibly(); channelFuture.channel().closeFuture().syncUninterruptibly(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } }

其中两个 handler 分别为:

  • TimeEncoder.java

将对象转换为 Bybebuf

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
public class TimeEncoder extends MessageToByteEncoder<UnixTime> { @Override protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out) throws Exception { // 对象序列化 long value = msg.value(); // 写入到 Bytebuf out.writeLong(value); } }
  • PojoTimeServerHandler.java

处理客户端 channel 链接时,发送时间到客户端。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class PojoTimeServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 字节写入时间戳 // 后续 encoder 会将其转换为 Bybebuf ctx.writeAndFlush(new UnixTime()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }

客户端

  • PojoTimeClient.java
  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class PojoTimeClient { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); ChannelFuture channelFuture = bootstrap.group(bossGroup) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new TimeDecoder()).addLast(new PojoTimeClientHandler()); } }) .connect("localhost", 8888); channelFuture.channel().closeFuture().syncUninterruptibly(); } finally { bossGroup.shutdownGracefully(); } } }

其中 handler 如下:

  • TimeDecoder.java

对时间戳进行解码为对象。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TimeDecoder extends ByteToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { // 将字节转化为对象 long value = in.readLong(); UnixTime unixTime = new UnixTime(value); // 将对象输出到结果 out.add(unixTime); } }
  • PojoTimeClientHandler.java

直接以对象的方式处理服务端信息。

  [java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PojoTimeClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { UnixTime unixTime = (UnixTime) msg; System.out.println("Receive data from server: " + unixTime); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }

个人感受

将转换和具体业务代码,使用 pipiline 的方式,可以提高复用率。

也可以使得代码变得简单专注。

实际使用

实际使用中,我们当然不会这么辛苦的去转换每一个对象。

直接结合 序列化框架概览 就可以非常简单的处理。

专业的事情交给专业的工具去处理。

拓展阅读

Netty-14-encoder 编码器

参考资料

《Netty 权威指南》

speaking-in-pojo-instead-of-bytebuf