四、Time协议
继续测试《netty5用户指南》中的Time协议。
1、一个封装时间的特殊的POJO类
首先实现UnixTime类:
package com.ydtf;
import java.util.Date;
public class UnixTime {
private final int value;
public UnixTime() {
this((int) (System.currentTimeMillis() / 1000L+ 2208988800L));
}
public UnixTime(int value) {
this.value = value;
}
public int value() {
return value;
}
@Override
public String toString() {
return new Date((value() - 2208988800L) *1000L).toString();
}
}
2、将ByteBuf转换为POJO
然后是TimeDecoder类:
package com.ydtf;
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
public class TimeDecoder extends ByteToMessageDecoder { // (1)
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in,
List<Object>out) throws Exception {
if (in.readableBytes()< 4) {
return;
}
out.add(new UnixTime(in.readInt()));
}
}
3、将POJO转换为ByteBuf
TimeEncoder,用于进行UnixTime –>ByteBuf的转换。
package com.ydtf;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class TimeEncoder extends MessageToByteEncoder<UnixTime> {
@Override
protected void encode(ChannelHandlerContext ctx, UnixTime msg, ByteBuf out)
throws Exception {
out.writeInt(msg.value());
}
}
4、服务端的处理
然后是服务端的handler:
package com.ydtf;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public classTimeServerHandler extendsChannelHandlerAdapter {
@Override
public voidchannelActive(ChannelHandlerContext ctx) {
ChannelFuture f = ctx.writeAndFlush(new UnixTime());
f.addListener(ChannelFutureListener.CLOSE);
}
@Override
public voidexceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
5、客户端的处理
客户端的handler:
package com.ydtf;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
public classTimeClientHandler extendsChannelHandlerAdapter {
@Override
public voidchannelRead(ChannelHandlerContext ctx, Object msg) {
UnixTime m = (UnixTime) msg;
System.out.println(m);
ctx.close();
}
@Override
public voidexceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
6、服务端主类
package com.ydtf;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioServerSocketChannel;
public class TimeServer {
private int port;
public TimeServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); // (2)
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class) // (3)
.childHandler(newChannelInitializer<SocketChannel>() { // (4)
@Override
public voidinitChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeEncoder(), new TimeServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128) // (5)
.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
ChannelFuture f = b.bind(port).sync(); // (7)
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new TimeServer(port).run();
}
}
7、客户端主类
packagecom.ydtf;
importio.netty.bootstrap.Bootstrap;
importio.netty.channel.ChannelFuture;
importio.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
importio.netty.channel.EventLoopGroup;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioSocketChannel;
publicclass TimeClient {
public static void main(String[] args)throws Exception {
String host = args[0];
int port = Integer.parseInt(args[1]);
EventLoopGroup workerGroup = newNioEventLoopGroup();
try {
Bootstrap b = new Bootstrap(); //(1)
b.group(workerGroup); // (2)
b.channel(NioSocketChannel.class);// (3)
b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
b.handler(newChannelInitializer<SocketChannel>() {
@Override
public voidinitChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(newTimeDecoder(), new TimeClientHandler());
}
});
// Start the client.
ChannelFuture f = b.connect(host,port).sync(); // (5)
// Wait until the connection isclosed.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
}
}
8、运行
在TimeServer.java上右键,Run as >> Java Application,启动服务端。
然后在TimeClient.java上右键,Run as >> Run Configurations…,在弹出的窗口中设置Name和Main Class:
Name设置一个和现有配置不重复的就可以了,比如TimeClient1、TimeClien(2)等。点击Mainclass右边的Search…按钮,选择TimeClient类。
然后点Arguments,添加两个运行参数localhost和8080:
然后点击窗口右下角的Run按钮。这是你将在客户端的Console窗口中看见一个日期输出。
如果想分别查看服务端和客户端的Console输出,请点击Display Selected Console按钮: