TIME协议的介绍 TIME协议
此协议提供了一个独立于站点的,机器可读的日期和时间信息。时间服务返回的是以秒数,是从1900年1月1日午夜到现在的秒数
详情查看 百度百科
实例功能介绍
在不接受任何请求时他会发送一个含32位的整数的消息,并且一旦消息发送就会立即关闭连接
因为我们将会忽略任何接收到的数据,而只是在连接被创建发送一个消息,所以这次我们不
能使用 channelRead() 方法了,代替他的是,我们需要覆盖 channelActive() 方法
Serverhandler代码
package com.shj.netty.handler;/**
* Created by shj on 2018/7/19.
*/
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
/**
* @version 1.0
* @className NettyServerHandler
* @Description
* DiscardServerHandler 继承自 ChannelInboundHandlerAdapter,这个类实现了
ChannelInboundHandler接口,ChannelInboundHandler 提供了许多事件处理的接口方法,
然后你可以覆盖这些方法。现在仅仅只需要继承 ChannelInboundHandlerAdapter 类而不是你
自己去实现接口方法。 (典型的适配器模式)
* @Author shj
* @Date 2018/7/19、18:05
*/
public class NettyTimeServerHandler extends ChannelInboundHandlerAdapter {
//channelActive() 将会在连接被建立并且准备进行通行时被调用
// 因此可以在此方法里完成一个代表当前时间的32位证书消息的构建工作
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 为了发送一个新的消息,我们需要分配一个包含这个消息的新的缓冲区,
// 因为需要写入一个32位的整数,因此我们需要一个至少4个字节的ByteBuf
//ChannelHandlerContext.alloc() 得到一个当前的ByteBufAllocator,然后分配一个新的缓冲。
ByteBuf time=ctx.alloc().buffer(4);
time.writeInt((int) (System.currentTimeMillis()/1000L+2208988800L));
//ByteBuf这个方法有两个指针,一个对应读操作,一个对应写操作,当你向ByteBuf里写入数据的时候
//写指针的索引就会增加,同时读指针的索引没有变化.读指针索引和写指针索引分别代表了消息的开始和结束
// 所以在使用netty的时候,不要再和NIO一样,调用flip()方法来切换读写
// 此外 ChannelHandlerContext的write()和writeAndFlush()返回的都是ChannelFuture对象
// 一个ChannelFuture代表了一个还没有发生的I/O操作, 即任何一个请求操作都不会马上被执行
//因为在netty中所有的操作都是异步的
// 由于clise()也会返回一个ChannelFuture 意味着可能并不会马上关闭
ChannelFuture channelFuture =ctx.writeAndFlush(time);
// 因此必须确保write()返回的ChannelFuture完成之后再调用close()
// 然后他的写操作已经完成他会通知他的监听者
// 此处是在ChannelFuture上增加一个ChannelFutureListener监听器
// 如果完成了写的操作,关闭channel
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
assert channelFuture==future;
ctx.close();
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
// 出现异常就关闭连接
cause.printStackTrace();
ctx.close();
}
}
server 代码
package com.shj.netty.server;
import com.shj.netty.handler.NettyTimeServerHandler;
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;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @version 1.0
* @className NettyTimeServer
* @Description
* @Author shj
* @Date 2018/7/20、13:55
*/
public class NettyTimeServer {
public static void main(String[] args) {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyTimeServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true);
// 绑定端口,开始接受进来的连接
ChannelFuture channelFuture =serverBootstrap.bind(888).sync();
// 等待服务器 socket关闭
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
clientHandler代码
package com.shj.netty.handler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Date;
/**
* @version 1.0
* @className NettyTimeClientHandler
* @Description
* @Author shj
* @Date 2018/7/20、13:57
*/
public class NettyTimeClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf= (ByteBuf) msg;
try{
long currentTime=(byteBuf.readUnsignedInt() - 2208988800L) * 1000L;;
System.out.println(new Date(currentTime));
ctx.close();
}finally {
byteBuf.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
client代码
package com.shj.netty.client;
import com.shj.netty.handler.NettyTimeClientHandler;
import io.netty.bootstrap.Bootstrap;
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;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* @version 1.0
* @className NettyTimeClient
* @Description
* @Author shj
* @Date 2018/7/20、11:45
*/
public class NettyTimeClient {
public static void main(String[] args) {
String host="127.0.0.1";
int port=888;
EventLoopGroup eventLoopGroup=new NioEventLoopGroup();
try {
// Bootstrap 与serverBootstrap类似,只是他是相对于非服务端的channel而言的
// 例如客户端或者无线传输模式的channel,那么它既是bossgroup,也是workerGroup
// 尽管客户端不需要使用到boss worker
Bootstrap bootstrap=new Bootstrap();
// 如果只指定了一个EventLoopGroup
bootstrap.group(eventLoopGroup)
// NioSocketChannel 在客户端channel被创建时使用
.channel(NioSocketChannel.class)
//
.option(ChannelOption.SO_KEEPALIVE,true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyTimeClientHandler());
}
});
// 启动客户端
ChannelFuture channelFuture=bootstrap.connect(host,port).sync();
// 等待连接关闭
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
}finally {
eventLoopGroup.shutdownGracefully();
}
}
}
测试结果
1 运行server
2 运行client
然后就可以看到
client 的控制台输出时间