(一) 说明:
这是一个使用netty框架的demo,客户端发送一个消息到服务端,服务端将消息原样发送到客户端。
(二) 服务端:
(1) netty服务器端的ChannelHandler业务核心处理逻辑
服务器端的处理器Handler命名为HelloWorldChannelHandler,继承自ChannelInboundHandlerAdapter适配器,有如下重载方法:

我们只实现它的读取方法channelRead和异常处理方法exceptionCaught。
/** * 业务核心处理逻辑 * @author comeCY * */ public class HelloWorldServerHandler extends ChannelInboundHandlerAdapter{ /** * 读取的方法 * 覆盖channelRead方法处理所有接收到的数据 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("server channelRead.."); //服务端读取 System.out.println(ctx.channel().remoteAddress()+"->Server :"+ msg.toString()); //服务端转发 ctx.write("server write :"+msg); ctx.flush(); //冲刷 } /** * 异常处理 */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); //打印异常堆栈跟踪 ctx.close(); //关闭通道 } }
(2) 引导服务器
- 创建 ServerBootstrap 实例来引导服务器并随后绑定
- 创建并分配一个 NioEventLoopGroup 实例来处理事件的处理,如接受新的连接和读/写数据。
- 指定本地 InetSocketAddress 给服务器绑定
- 通过 EchoServerHandler 实例给每一个新的 Channel 初始化
- 最后调用 ServerBootstrap.bind() 绑定服务器
public class HelloWorldServer { private int port; public HelloWorldServer(int port) { this.port = port; } public void start() throws Exception{ EventLoopGroup bossGroup = new NioEventLoopGroup(1); //创建EventLoopGroup EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap sbs = new ServerBootstrap() .group(bossGroup,workerGroup) //创建ServerBootstrap .channel(NioServerSocketChannel.class) //指定使用 NIO 的传输 Channel .localAddress(new InetSocketAddress(port)) //设置 socket 地址使用所选的端口 .childHandler(new ChannelInitializer<SocketChannel>() { //添加 到 Channel 的 ChannelPipeline protected void initChannel(SocketChannel ch) throws Exception { //添加字符串编码和解码器 ch.pipeline().addLast("decoder", new StringDecoder()); ch.pipeline().addLast("encoder", new StringEncoder()); //添加 HelloWorldSrverHandler ch.pipeline().addLast(new HelloWorldServerHandler()); }; }).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); //启用心跳保活机制 // 绑定端口,开始接收进来的连接 ChannelFuture future = sbs.bind(port).sync(); System.out.println("Server start listen at " + port ); future.channel().closeFuture().sync(); //关闭 channel 和 块,直到它被关闭 } finally { bossGroup.shutdownGracefully(); //关闭 EventLoopGroup,释放所有资源 workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 8080; } new HelloWorldServer(port).start(); //呼叫服务器的start方法 } }
(三) 客户端:
(1) 客户端Handler
HelloWorldClientHandler也是继承自ChannelInboundHandlerAdapter,实现方法channelActive,channelRead,exceptionCaught与服务端类似。
public class HelloWorldClientHandler extends ChannelInboundHandlerAdapter{ @Override public void channelActive(ChannelHandlerContext ctx) { //当被通知该 channel 是活动的时候打印 System.out.println("HelloWorldClientHandler Active"); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { //记录接收到的消息 System.out.println("HelloWorldClientHandler read Message:"+msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); //记录日志错误并关闭 channel ctx.close(); } }
(2) 引导客户端
- Bootstrap 被创建来初始化客户端
- NioEventLoopGroup 实例被分配给处理该事件的处理,这包括创建新的连接和处理 入站和出站数据
- InetSocketAddress 为连接到服务器而创建
- HelloWorldClientHandler 将被安装在 pipeline 当连接完成时
- Bootstrap.connect()被调用连接到远程的服务器
public class HelloWorldClient { static final String HOST = System.getProperty("host", "127.0.0.1"); static final int PORT = Integer.parseInt(System.getProperty("port", "8080")); public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); //创建 Bootstrap /* 指定 EventLoopGroup 来处理客户端事件。由于我们使用 NIO 传输,所以用到了 NioEventLoopGroup 的实现*/ b.group(group) .channel(NioSocketChannel.class) //使用的 channel 类型是一个用于 NIO 传输 .option(ChannelOption.TCP_NODELAY, true) //关闭Nagle算法,实时发送数据 .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { // TODO Auto-generated method stub ChannelPipeline p = ch.pipeline(); p.addLast("decoder", new StringDecoder()); p.addLast("encoder", new StringEncoder()); p.addLast(new HelloWorldClientHandler()); } }); ChannelFuture future = b.connect(HOST, PORT).sync(); //连接到远程;等待连接完成 //客户端写入 future.channel().writeAndFlush("Hello Netty Server, I am a common client..."); future.channel().closeFuture().sync(); //阻塞直到 Channel 关闭 } finally { group.shutdownGracefully(); //调用 shutdownGracefully() 来关闭线程池和释放所有资源 } } }
(四) 运行效果:
(1) 服务端

(2) 客户端

(五) 结语
学习博客:
参考书籍: