[Netty] - Netty入门(最简单的Netty客户端/服务器程序)
Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的。那么Netty就是一种简化操作的一个成熟的网络IO编程框架。这里简单介绍一个程序,代码是《netty in action》里面的,不过那个里面的实例有点问题,反正我没有跑成功,修改后成功。直接上代码:
一、服务器编写
Server代码,监听连接
1 package com.gerry.netty.server; 2 3 import io.netty.bootstrap.ServerBootstrap; 4 import io.netty.channel.ChannelFuture; 5 import io.netty.channel.ChannelInitializer; 6 import io.netty.channel.EventLoopGroup; 7 import io.netty.channel.nio.NioEventLoopGroup; 8 import io.netty.channel.socket.SocketChannel; 9 import io.netty.channel.socket.nio.NioServerSocketChannel; 10 11 public class EchoServer { 12 private final int port; 13 14 public EchoServer(int port) { 15 this.port = port; 16 } 17 18 public void start() throws Exception { 19 EventLoopGroup group = new NioEventLoopGroup(); 20 try { 21 ServerBootstrap sb = new ServerBootstrap(); 22 sb.group(group) // 绑定线程池 23 .channel(NioServerSocketChannel.class) // 指定使用的channel 24 .localAddress(this.port)// 绑定监听端口 25 .childHandler(new ChannelInitializer<SocketChannel>() { // 绑定客户端连接时候触发操作 26 27 @Override 28 protected void initChannel(SocketChannel ch) throws Exception { 29 System.out.println("connected...; Client:" + ch.remoteAddress()); 30 ch.pipeline().addLast(new EchoServerHandler()); // 客户端触发操作 31 } 32 }); 33 ChannelFuture cf = sb.bind().sync(); // 服务器异步创建绑定 34 System.out.println(EchoServer.class + " started and listen on " + cf.channel().localAddress()); 35 cf.channel().closeFuture().sync(); // 关闭服务器通道 36 } finally { 37 group.shutdownGracefully().sync(); // 释放线程池资源 38 } 39 } 40 41 public static void main(String[] args) throws Exception { 42 new EchoServer(65535).start(); // 启动 43 } 44 }
具体的处理客户端连接的代码
1 package com.gerry.netty.server; 2 3 import io.netty.buffer.Unpooled; 4 import io.netty.channel.ChannelFutureListener; 5 import io.netty.channel.ChannelHandlerContext; 6 import io.netty.channel.ChannelInboundHandlerAdapter; 7 8 public class EchoServerHandler extends ChannelInboundHandlerAdapter { 9 @Override 10 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 11 System.out.println("server channelRead...; received:" + msg); 12 ctx.write(msg); 13 } 14 15 @Override 16 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 17 System.out.println("server channelReadComplete.."); 18 // 第一种方法:写一个空的buf,并刷新写出区域。完成后关闭sock channel连接。 19 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); 20 //ctx.flush(); // 第二种方法:在client端关闭channel连接,这样的话,会触发两次channelReadComplete方法。 21 //ctx.flush().close().sync(); // 第三种:改成这种写法也可以,但是这中写法,没有第一种方法的好。 22 } 23 24 @Override 25 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 26 System.out.println("server occur exception:" + cause.getMessage()); 27 cause.printStackTrace(); 28 ctx.close(); // 关闭发生异常的连接 29 } 30 }
二、客户端编写
具体的连接代码
1 package com.gerry.netty.client; 2 3 import io.netty.bootstrap.Bootstrap; 4 import io.netty.channel.ChannelFuture; 5 import io.netty.channel.ChannelInitializer; 6 import io.netty.channel.EventLoopGroup; 7 import io.netty.channel.nio.NioEventLoopGroup; 8 import io.netty.channel.socket.SocketChannel; 9 import io.netty.channel.socket.nio.NioSocketChannel; 10 11 import java.net.InetSocketAddress; 12 13 public class EchoClient { 14 private final String host; 15 private final int port; 16 17 public EchoClient() { 18 this(0); 19 } 20 21 public EchoClient(int port) { 22 this("localhost", port); 23 } 24 25 public EchoClient(String host, int port) { 26 this.host = host; 27 this.port = port; 28 } 29 30 public void start() throws Exception { 31 EventLoopGroup group = new NioEventLoopGroup(); 32 try { 33 Bootstrap b = new Bootstrap(); 34 b.group(group) // 注册线程池 35 .channel(NioSocketChannel.class) // 使用NioSocketChannel来作为连接用的channel类 36 .remoteAddress(new InetSocketAddress(this.host, this.port)) // 绑定连接端口和host信息 37 .handler(new ChannelInitializer<SocketChannel>() { // 绑定连接初始化器 38 @Override 39 protected void initChannel(SocketChannel ch) throws Exception { 40 System.out.println("connected..."); 41 ch.pipeline().addLast(new EchoClientHandler()); 42 } 43 }); 44 System.out.println("created.."); 45 46 ChannelFuture cf = b.connect().sync(); // 异步连接服务器 47 System.out.println("connected..."); // 连接完成 48 49 cf.channel().closeFuture().sync(); // 异步等待关闭连接channel 50 System.out.println("closed.."); // 关闭完成 51 } finally { 52 group.shutdownGracefully().sync(); // 释放线程池资源 53 } 54 } 55 56 public static void main(String[] args) throws Exception { 57 new EchoClient("127.0.0.1", 65535).start(); // 连接127.0.0.1/65535,并启动 58 } 59 }
连接成功后,具体的通信代码
1 package com.gerry.netty.client; 2 3 import java.nio.charset.Charset; 4 5 import io.netty.buffer.ByteBuf; 6 import io.netty.buffer.ByteBufUtil; 7 import io.netty.buffer.Unpooled; 8 import io.netty.channel.ChannelHandlerContext; 9 import io.netty.channel.SimpleChannelInboundHandler; 10 import io.netty.util.CharsetUtil; 11 12 public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { 13 14 @Override 15 public void channelActive(ChannelHandlerContext ctx) throws Exception { 16 System.out.println("client channelActive.."); 17 ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); // 必须有flush 18 19 // 必须存在flush 20 // ctx.write(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); 21 // ctx.flush(); 22 } 23 24 @Override 25 protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { 26 System.out.println("client channelRead.."); 27 ByteBuf buf = msg.readBytes(msg.readableBytes()); 28 System.out.println("Client received:" + ByteBufUtil.hexDump(buf) + "; The value is:" + buf.toString(Charset.forName("utf-8"))); 29 //ctx.channel().close().sync();// client关闭channel连接 30 } 31 32 @Override 33 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 34 cause.printStackTrace(); 35 ctx.close(); 36 } 37 38 }
三、结果
先运行server,在运行client即可。