搭建一个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();}
运行结果:服务端收到特定的消息,客户端收到服务端返回的时间戳,。