1. ChannelHandler和业务逻辑
@Sharable // 一个ChannelHandler可以被多个Channel共享 public class EchoServiceHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // 对每个传入的消息都要调用 ByteBuf in = (ByteBuf) msg; ctx.write(in); // 将接收到的消息写给发送者 } @Override public void channelReadComplete(ChannelHandlerContext ctx) { // 通知ChannelInboundHandler对channelRead()的调用是当前批量中的最后一条 ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); // 冲刷到远程节点并关闭监听 } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // 读取操作期间有异常抛出时调用 cause.printStackTrace(); // 打印异常栈跟踪 ctx.close(); // 关闭Channel } }
2. 引导服务器
public class EchoService { private final int port; public EchoService (int port) { this.port = port; } public static void main(String[] args) throws Exception { int port = Integer.parseInt(args[0]); new EchoService(port).start(); } public void start() throws Exception { final EchoServerHandler serverHandler = new EchoServerHandler(); EventLoopGroup group = new NioEventLoopGroup(); // 进行事件的处理,如接受新连接及读写数据 try { ServerBootstrap b = new ServerBootstrap(); b.group(group) .channel(NioServerSocketChannel.class) // 指定所使用的NIO传输Channel .localAddress(new InetSocketAddress(port)) // 使用指定的端口设置套接字地址,服务器将绑定到这个地址监听新的连接请求 .childHandler(new ChannelInitializer<SocketChannel>(){ // 一个新的连接会创建一个新的子Channel,ChannelInitializer将会把EchoServiceHandler实例添加到该Channel的ChannelPipeline中 @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(serverHandler); } }); ChannelFuture f = b.bind().sync(); // 异步绑定服务器,调用sync()方法阻塞等待直到绑定完成 f.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); // 释放所有资源,包括所有被创建的线程 } } }
3. 通过ChannelHandler实现客户端逻辑
@Sharable public class EcheClientHandler extends SimpleChannelInboundHandler<ByteBuf> { @Override public void channelActive(ChannelHandlerContext ctx) { // 与服务器建立连接后调用 ctx.writeAndFlush(Unpooled.copiedBuffer("...", CharsetUtil.UTF_8)); } @Override public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) { // 从服务器接受消息时调用 System.out.println("client received" + in.toString(CharsetUtil.UTF_8)); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // 发生异常时记录错误并关闭Channel cause.printStackTrace(); ctx.close(); } }
4. 引导客户端
public class EchoClient { private final String host; private final int port; public EchoClient (String host, int port) { this.host = host; this.port = port; } public static void main(String[] args) throws Exception { String host = args[0]; int port = Integer.parseInt(args[1]); new EchoClient(host, port).start(); } public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioServerSocketChannel.class) .remoteAddress(new InetSocketAddress(host, port)) .handler(new ChannelInitializer<SocketChannel>(){ @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new EchoClientHandler()); } }); ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); } } }