1、服务端:
package com.suirui.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* Created by zongx on 2019/12/26.
*/
public class TimeServer {
public static void main(String[] args) {
int port = 9999;
if (args != null && args.length > 0) {
port = Integer.valueOf(args[0]);
}
new TimeServer().bind(port);
}
public void bind(int port) {
//配置服务端的NIO线程组
//两个线程组的原因是:
// 一个用于服务端接收客户端连接
//一个用于进行socketChannel网络读写
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//ServerBootstrap 是netty的辅助启动类
ServerBootstrap b = new ServerBootstrap();
// .group传入两个线程组
// .channel设置创建的Channel类型为NioServerSocketChannel
// .option 配置NioServerSocketChannel的TCP参数
// .childHandler绑定IO事件的处理类 类似reactor模式中的handler:进行连接与读写socket。
// ChildChannelHandler会重写initChannel,保证当创建NioServerSocketChannel成功之后,再进行初始化。
/*************.handler 与 .childHandler的区别*******/
// handler()和childHandler()的主要区别是,handler()是发生在初始化的时候,childHandler()是发生在客户端连接之后。
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChildChannelHandler());
//绑定端口,等待成功
try {
//.sync()是同步阻塞接口,等待绑定操作完成
//ChannelFuture主要用于异步操作的通知回调
ChannelFuture f = b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer {
//注意此处不要使用ServerSocketChannel,否则客户端无法启动端口
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeServerHandler());
}
}
}
package com.suirui.server;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
/**
* Created by zongx on 2019/12/26.
*/
public class TimeServerHandler extends SimpleChannelInboundHandler {
private int count =0;
@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("TimeServer 收到指令: " + body + ", 当前次数 :" + count++);
String currentTime = "query time order".equalsIgnoreCase(body)? LocalDateTime.now().toString():"bad order";
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
2、客户端
package com.suirui.client;
import com.suirui.server.TimeServerHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
/**
* Created by zongx on 2019/12/26.
*/
public class TimeClient {
public static void main(String[] args) throws Exception {
int port = 9999;
if (args != null && args.length > 0) {
port = Integer.valueOf(args[0]);
}
new TimeClient().connect("127.0.0.1", port);
}
private void connect(String host, int port) throws Exception {
//配置客户端NIO线程组
NioEventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChildChannelHandler());
//发起异步连接操作
ChannelFuture f = b.connect(host, port).sync();
//等待客户端链路关闭
f.channel().closeFuture().sync();
}
private class ChildChannelHandler extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
}
}
}
package com.suirui.client;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* Created by zongx on 2019/12/26.
*/
public class TimeClientHandler extends SimpleChannelInboundHandler {
private final byte[] order;
private int count = 0;
public TimeClientHandler() {
order = "query time order".getBytes();
}
@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("当前时间为: " + body + ", 当前次数 " + count++);
System.out.println();
System.out.println();
System.out.println();
Thread.sleep(1000);
ByteBuf firstMessage = Unpooled.buffer(order.length);
firstMessage.writeBytes(order);
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// for (int i = 0; i < 100; i++) {
ByteBuf firstMessage = Unpooled.buffer(order.length);
firstMessage.writeBytes(order);
ctx.writeAndFlush(firstMessage);
// }
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
结果: