netty echo例子
netty使用方法:
1. 选择事件处理线程池EventLoopGroup, 要与下面的管道选择对应名称, 服务端要两个(一个是接收客户端连接,另一个是处理客户端请求), 客户端只需要一个(处理客户端请求)
2. 创建Bootstrap对象, 配置事件处理线程池(上面new的Group)
3. 设置管道(有NioSocketChannel, EpollSocketChannel(linux下可用), LocalServerChannel(可能本地通信, 127.0.0.1之间))
4. 设置绑定的端口和主机名 如果是服务端就localAddress(8080), 如果是客户端就remoteAddress("127.0.0.1", 8080)
5. 绑定客户端处理类服务端使用childHandler, 客户端使用handler
6. 调用connect()方法, 阻塞直到连接成功
7. 阻塞直到channel关闭
8. 关闭线程池
EchoServer.java
package org.example.echo; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; public class EchoServer { public static void main(String[] args) { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup); serverBootstrap.channel(NioServerSocketChannel.class).localAddress(8080); //serverBootstrap.channel(EpollServerSocketChannel.class); serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoServerHandler()); } }); ChannelFuture channelFuture = serverBootstrap.bind().sync(); // 绑定端口,并同步等待成功 channelFuture.channel().closeFuture().sync(); // 同步等待关闭channel } catch (Exception ex) { try { workerGroup.shutdownGracefully().sync(); } catch(Exception e) { } try { bossGroup.shutdownGracefully(); } catch (Exception e) {} } } }
EchoServerHandler.java
package org.example.echo; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.util.CharsetUtil; import java.net.SocketAddress; //@ChannelHandler.Sharable 标示一个Channel- Handler可以被多个Channel安全地共享 public class EchoServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); SocketAddress address = ctx.channel().localAddress(); System.out.println("收到连接 address:" + address.toString()); // ctx.writeAndFlush("this is server's msg"); //直接写字符串收不到 // ctx.writeAndFlush("this is server's msg".getBytes()); //直接写字节数组收不到 ctx.writeAndFlush(Unpooled.copiedBuffer("hello, this is server:" + Thread.currentThread().getId(), CharsetUtil.UTF_8)); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { SocketAddress address = ctx.channel().localAddress(); System.out.println("连接断开 address:" + address.toString()); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //ctx.fireChannelRead(msg); ByteBuf in = (ByteBuf) msg; // 打印消息 System.out.println("Server received: " + in.toString(io.netty.util.CharsetUtil.UTF_8)); // 返回给客户端 ctx.writeAndFlush(in); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
EchoClient.java
package org.example.echo; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; public class EchoClient { public static void main(String[] args) { NioEventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) //指定客户端处理事件group .channel(NioSocketChannel.class); //NioSocketChannel bootstrap.remoteAddress("127.0.0.1", 8080); //指定服务器地址 bootstrap.handler(new ChannelInitializer<NioSocketChannel>(){ @Override protected void initChannel(NioSocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); } }); try { ChannelFuture future = bootstrap.connect().sync(); //阻塞并连结到远程结点 future.channel().closeFuture().sync(); //阻塞直到channel关闭 } catch (Exception ex){ } finally { group.shutdownGracefully(); //关闭线程池 } } }
EchoClientHandler.java
package org.example.echo; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.CharsetUtil; import java.net.SocketAddress; public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> { public EchoClientHandler() { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { SocketAddress address = ctx.channel().localAddress(); System.out.println("建立连接 address:" + address.toString()); //直按发字符串或字节数组, 服务端收不到, 要使用Unpooled.copiedBuffer包裹 ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8)); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { SocketAddress address = ctx.channel().localAddress(); System.out.println("连接断开 address:" + address.toString()); } @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { //ctx.fireChannelRead(msg); ByteBuf in = (ByteBuf) msg; // 打印消息 System.out.println("收到回应: " + in.toString(io.netty.util.CharsetUtil.UTF_8)); // 返回给客户端 Thread.sleep(1000); //直按发字符串或字节数组, 服务端收不到, 要使用Unpooled.copiedBuffer包裹 ctx.writeAndFlush(Unpooled.copiedBuffer("current Time:" + System.currentTimeMillis(), CharsetUtil.UTF_8)); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }