1、时间服务器介绍
服务端启动,等待时间客户端连接。客户连接过程中向时间服务端发送“QUERY TIME ORDER”获取当前时间指令。
服务端成功读取请求指令后进行判断并根据指令条件进行返回信息显示到客户端。
2、服务端
TimeServer.java
package com.moreday.netty.nio;
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;
/**
* 时间服务器服务端TimeServer
* @author 寻找手艺人
*
*/
public class TimeServer {
public void bind(int port) throws Exception{
//配置服务端线程组
EventLoopGroup parentGroup = new NioEventLoopGroup();
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChildChannelHandler());
//绑定端口,同步等待成功
ChannelFuture future = b.bind(port).sync();
//等待服务端监听端口关闭
future.channel().closeFuture().sync();
} finally {
// TODO: handle finally clause
//优雅退出,释放线程资源
parentGroup.shutdownGracefully();
childGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new TimeServerHandler());
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
if(args!=null&&args.length>0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
// TODO: handle exception
}
new TimeServer().bind(port);
}
}
}
TimeServerHandler.java
package com.moreday.netty.nio;
import java.util.Date;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 时间服务器服务端TimeServerHandler
* @author 寻找手艺人
*
*/
public class TimeServerHandler extends SimpleChannelInboundHandler<Object> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req,"UTF-8");
System.out.println("The Time Server receive Order:"+body);
String currentSysTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?new Date(System.currentTimeMillis()).toString():"BAD ORDER";
ByteBuf resq = Unpooled.copiedBuffer(currentSysTime.getBytes());
ctx.writeAndFlush(resq);
}
}
3、客户端
TimeClient.java
package com.moreday.netty.nio;
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.nio.NioSocketChannel;
/**
* 时间服务器客户端端TimeClient
* @author 寻找手艺人
*
*/
public class TimeClient {
public void connect(int port,String host) throws Exception {
//配置客户端NIO线程
EventLoopGroup group = new NioEventLoopGroup();
try {
//BootStrap 和 ServerBootstrap 类似,不过他是对非服务端的 channel 而言
//,比如客户端或者无连接传输模式的 channel。
Bootstrap b = new Bootstrap();
//NioSocketChannel这个类在客户端channel 被创建时使用
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// TODO Auto-generated method stub
ch.pipeline().addLast(new TimeClientHandler());
}
});
//发起异步链接操作,启动客户端
//我们用 connect() 方法代替了 bind() 方法
ChannelFuture f = b.connect(host, port).sync();
//等待客户端链路关闭
f.channel().closeFuture().sync();
} finally {
//优雅退出
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port = 8080;
if(args!=null && args.length>0) {
try {
port = Integer.valueOf(args[0]);
} catch (Exception e) {
// TODO: handle exception
}
}
new TimeClient().connect(port, "127.0.0.1");
}
}
TimeClientHandler.java
package com.moreday.netty.nio;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 时间服务器客户端端TimeClientHandler
* @author 寻找手艺人
*
*/
public class TimeClientHandler extends SimpleChannelInboundHandler<Object> {
/**
* 在连接被创建发送一个消息,
* 所以这次我们不能使用 channelRead() 方法了,
* 代替他的是,我们需要覆盖 channelActive() 方法
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
byte[] req = "QUERY TIME ORDER".getBytes();
ByteBuf msg = Unpooled.copiedBuffer(req);
ctx.writeAndFlush(msg);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] resp = new byte[buf.readableBytes()];
buf.readBytes(resp);
String body = new String(resp,"UTF-8");
System.out.println("The Time Client receive Order:"+body);
}
}
4、运行结果
客户端
服务端
到此,Netty应用时间服务器编写完成,下面博文将介绍Netty4.x 粘包、拆包问题及问题的解决方法。