搭建一个netty应用demo
before:先在pom引入jar包:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
1)先搭建服务端
public class TimeServer {
public void bind(int port) throws Exception {
/**
* 创建两个线程组,它包含一nio线程,专门用于处理网络事件的处理,实际上他们就是reactor线程组(专门用于服务端接受客户端的链接)
* 另一个是:进行socketchannel的网络读写,
*/
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
/**
* 创建一个serverbootstrap对象,是启动nio服务端的辅助启动类,
*/
ServerBootstrap b = new ServerBootstrap();
/**
* 将两个线程组当做参数传递到辅助类,创建serversocketchannel类,配置tcp参数, io处理类,类似于reactor模式中handler类
*/
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler());
/**
* 绑定端口,调用同步阻塞方法sync等待绑定完成,完成后返回一个ChannelFuture,主要作用于异步操作的通知回调
*/
ChannelFuture f = b.bind(port).sync();
/**
* 等待服务链路关闭之后main方法函数退出,类似于thread.sleep
*/
f.channel().closeFuture().sync();
} catch (Exception e) {
// TODO: handle exception
} finally {
/**
* 释放资源
*/
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel arg0) throws Exception {
arg0.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 (Exception e) {
// TODO: handle exception
}
}
new TimeServer().bind(port);
}
}
2)服务端 读写的操作类(也就是以后在那读写写数据的地方)
/**
* ChannelHandlerAdapter主要负责对网络时间进行读写操作,通常我们只要关心channelRead,和exceptionCaught方法就可
*/
public class TimeServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
/**
* 消息经过类型转换,讲msg转为bytebuf,通过buf.readableBytes()方法获取缓存区可读的字节数,根据可读的字节数创建一个byte数组,
* 然后通过buf.readBytes把可读的数组复制到新建的byte req数据组中,最后通过new string构造函数获取请求消息,然后对消息进行处理,
* 有“关键字”就发送异步应答消息给客户端
*/
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 currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis())
.toString() : "BAD ORDER";
ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
ctx.write(resp);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();//将消息发送队列中的消息写入到socketchannel中发送给对方,(一般是将消息放到缓存数组中,通过调用flush 才讲缓存中数据全部发给socketchannel)
}
@Override
public void exceptionCaught(ChannelHandlerContext arg0, Throwable arg1) throws Exception {
arg0.close();
}
}
3)客户端类
/**
* 客户端开发
*/
public class TimeClient {
public void connect(int port ,String host)throws Exception{
NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
try {
/**
* 创建客户端处理io的读写nioeventlopgroup线程组,然后创建客户端辅助启动类bootstrap,
* 注意,这里使用的channel需要设置为niosocketchannel,然后为其添加handler,,然后初始化等
*
*/
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(nioEventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
/**
* 启动辅助类,发起异步链接,
*/
ChannelFuture future=bootstrap.connect(host,port).sync();
future.channel().closeFuture().sync();
}finally {
nioEventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port=8080;
if(args!=null&& args.length>0){
port=Integer.valueOf(args[0]);
}
new TimeClient().connect(port,"127.0.0.1");
}
}
4)客户端读写数据的地方(实现方式和server实现的接口一样)
public class TimeClientHandler extends ChannelHandlerAdapter{
private static final Logger logger= Logger.getLogger(TimeClientHandler.class.getName());
private final ByteBuf firstMessage;
public TimeClientHandler(){
byte[] req="QUERY TIME ORDER".getBytes();
firstMessage = Unpooled.buffer(req.length);
firstMessage.writeBytes(req);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf byteBuf = (ByteBuf) msg;
byte[] req = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(req);
String s = new String(req, "UTF-8");
System.out.println("Now is :"+s);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.info("exceptionCaught from downstream :"+cause.getMessage());
ctx.close();}
运行结果:服务端收到特定的消息,客户端收到服务端返回的时间戳,。