Handler如何使用在前面的例子中已经有了示范,那么同样是扩展自ChannelHandler的Encoder和Decoder,与Handler混合后又是如何使用的?本文将通过一个实际的小例子来展示它们的用法。
该例子模拟一个Server和Client,两者之间通过http协议进行通讯,在Server内部通过一个自定义的StringDecoder把httprequest转换成String。Server端处理完成后,通过StringEncoder把String转换成httpresponse,发送给客户端。具体的处理流程如图所示:
其中红色框中的Decoder、Encoder及request都是Netty框架自带的,灰色框中的三个类是我自己实现的。
Server端的类有:Server StringDecoder BusinessHandler StringEncoder四个类。
1.Server.java启动netty服务,并注册handler、coder,注意注册的顺序:
package com.bijian.netty.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; // 测试coder 和 handler 的混合使用 public class Server { public void start(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { // 都属于ChannelOutboundHandler,逆序执行 ch.pipeline().addLast(new HttpResponseEncoder()); ch.pipeline().addLast(new StringEncoder()); // 都属于ChannelIntboundHandler,按照顺序执行 ch.pipeline().addLast(new HttpRequestDecoder()); ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new BusinessHandler()); } }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { Server server = new Server(); server.start(8000); } }
2.StringDecoder.java把httpRequest转换成String,其中ByteBufToBytes是一个工具类,负责对ByteBuf中的数据进行读取
package com.bijian.netty.server; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bijian.netty.util.ByteBufToBytes; public class StringDecoder extends ChannelInboundHandlerAdapter { private static Logger logger = LoggerFactory.getLogger(StringDecoder.class); private ByteBufToBytes reader; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { logger.info("StringDecoder : msg's type is " + msg.getClass()); if (msg instanceof HttpRequest) { HttpRequest request = (HttpRequest) msg; reader = new ByteBufToBytes((int) HttpHeaders.getContentLength(request)); } if (msg instanceof HttpContent) { HttpContent content = (HttpContent) msg; reader.reading(content.content()); if (reader.isEnd()) { byte[] clientMsg = reader.readFull(); logger.info("StringDecoder : change httpcontent to string "); ctx.fireChannelRead(new String(clientMsg)); } } } }
3.BusinessHandler.java具体处理业务的类,把客户端的请求打印出来,并向客户端发送信息
package com.bijian.netty.server; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BusinessHandler extends ChannelInboundHandlerAdapter { private Logger logger = LoggerFactory.getLogger(BusinessHandler.class); @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { String clientMsg = "client said : " + (String) msg; logger.info("BusinessHandler read msg from client :" + clientMsg); ctx.write("I am very OK!"); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } }
4.StringEncoder.java把字符串转换成HttpResponse
package com.bijian.netty.server; import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaders.Values; // 把String转换成httpResponse public class StringEncoder extends ChannelOutboundHandlerAdapter { private Logger logger = LoggerFactory.getLogger(StringEncoder.class); @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { logger.info("StringEncoder response to client."); String serverMsg = (String) msg; FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(serverMsg .getBytes())); response.headers().set(CONTENT_TYPE, "text/plain"); response.headers().set(CONTENT_LENGTH, response.content().readableBytes()); response.headers().set(CONNECTION, Values.KEEP_ALIVE); ctx.write(response); ctx.flush(); } }
Client端有两个类:Client.java、ClientInitHandler.java
1.Client.java与Server端建立连接,并向Server端发送HttpRequest请求。
package com.bijian.netty.client; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.codec.http.HttpVersion; import java.net.URI; public class Client { public void connect(String host, int port) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new HttpResponseDecoder()); ch.pipeline().addLast(new HttpRequestEncoder()); ch.pipeline().addLast(new ClientInitHandler()); } }); // Start the client. ChannelFuture f = b.connect(host, port).sync(); URI uri = new URI("http://127.0.0.1:8000"); String msg = "Are you ok?"; DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uri.toASCIIString(), Unpooled.wrappedBuffer(msg.getBytes())); request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes()); f.channel().write(request); f.channel().flush(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { Client client = new Client(); client.connect("127.0.0.1", 8000); } }
2.ClientInitHandler.java从Server端读取响应信息
package com.bijian.netty.client; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import com.bijian.netty.util.ByteBufToBytes; public class ClientInitHandler extends ChannelInboundHandlerAdapter { private ByteBufToBytes reader; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; if (HttpHeaders.isContentLengthSet(response)) { reader = new ByteBufToBytes((int) HttpHeaders.getContentLength(response)); } } if (msg instanceof HttpContent) { HttpContent httpContent = (HttpContent) msg; ByteBuf content = httpContent.content(); reader.reading(content); content.release(); if (reader.isEnd()) { String resultStr = new String(reader.readFull()); System.out.println("Server said:" + resultStr); } } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.close(); } }
工具类:ByteBufToBytes 对ByteBuf的数据进行读取,支持流式读取(reading 和 readFull方法结合使用)
ByteBufToBytes.java
package com.bijian.netty.util; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; public class ByteBufToBytes { private ByteBuf temp; private boolean end = true; public ByteBufToBytes(int length) { temp = Unpooled.buffer(length); } public void reading(ByteBuf datas) { datas.readBytes(temp, datas.readableBytes()); if (this.temp.writableBytes() != 0) { end = false; } else { end = true; } } public boolean isEnd() { return end; } public byte[] readFull() { if (end) { byte[] contentByte = new byte[this.temp.readableBytes()]; this.temp.readBytes(contentByte); this.temp.release(); return contentByte; } else { return null; } } public byte[] read(ByteBuf datas) { byte[] bytes = new byte[datas.readableBytes()]; datas.readBytes(bytes); return bytes; } }
运行结果:
23:22:40.846 INFO com.bijian.netty.server.StringDecoder 22 channelRead - StringDecoder : msg's type is class io.netty.handler.codec.http.DefaultHttpRequest 23:22:40.848 INFO com.bijian.netty.server.StringDecoder 22 channelRead - StringDecoder : msg's type is class io.netty.handler.codec.http.DefaultLastHttpContent 23:22:40.848 INFO com.bijian.netty.server.StringDecoder 34 channelRead - StringDecoder : change httpcontent to string 23:22:40.849 INFO com.bijian.netty.server.BusinessHandler 16 channelRead - BusinessHandler read msg from client :client said : Are you ok? 23:22:40.849 INFO com.bijian.netty.server.StringEncoder 28 write - StringEncoder response to client.
可以看到执行顺序为:StringDecoder、BusinessHandler、StringEncoder,其它的都是Netty自身的,没有打印。
通过该实例证明,Encoder、Decoder的本质也是Handler,它们的执行顺序、使用方法与Handler保持一致。
执行顺序是:Encoder 先注册的后执行,与OutboundHandler一致;Decoder是先注册的先执行,与InboundHandler一致。
文章来源:http://blog.csdn.net/u013252773/article/details/21564301
相关推荐
在本篇“Netty4.0学习笔记系列之二:Handler的执行顺序”中,我们将深入探讨Netty中的Handler处理链以及它们的执行流程。 首先,Netty 中的 ChannelHandler 是处理 I/O 事件或拦截 I/O 操作的核心组件。每个 ...
在本篇“Netty4.0学习笔记系列之五:自定义通讯协议”中,我们将深入探讨如何在Netty框架下构建和实现自己的通信协议。Netty是一个高性能、异步事件驱动的网络应用框架,广泛应用于Java领域的服务器开发,如网络游戏...
在本篇Netty4.0学习笔记系列之六中,我们将深入探讨Netty框架如何支持多种通讯协议,以及它在实现高效、灵活的网络通信中的关键特性。Netty是一个高性能、异步事件驱动的网络应用框架,适用于开发服务器和客户端的...
Netty4.0学习笔记系列之三是关于构建简单的HTTP服务的教程,这主要涉及网络编程、服务器开发以及Java NIO(非阻塞I/O)的相关知识。Netty是一个高性能、异步事件驱动的网络应用程序框架,它使得开发可伸缩且稳定的...
在本文中,我们将深入探讨Netty 4.0的学习笔记,特别是关于Server与Client之间的通信机制。 首先,我们要理解Netty的核心概念——NIO(非阻塞I/O)。Netty基于Java NIO库构建,它提供了更高级别的API,简化了多路...
Netty4.0全部jar包.开发时候只需要倒入总的哪一个netty4.0.jar就行了 后缀为resources.jar的全部是源码。 简单的代码例子在netty-example-resources.jar里面。
Netty 是一个高性能、异步事件驱动...rrkd-file-client和rrkd-file-server这两个文件可能包含了实现上述功能的客户端和服务端代码示例,通过分析和学习这些代码,开发者可以更好地理解和应用Netty进行文件上传的实践。
Netty 是一个高性能、异步事件驱动的网络应用...官方示例通常覆盖了基础到高级的各种用法,是理解和掌握 Netty4.0 的良好起点。你可以从 netty-4.0 压缩包中的源代码开始,逐步分析和实践,从而提升你的网络编程技能。
NIO socket开发,netty4.0工具包。
总的来说,这个"Netty4.0 http案例"涵盖了如何使用Netty构建高效、可扩展的HTTP服务器和客户端,以及如何处理JSON数据。通过理解这些知识点,你不仅可以实现基本的HTTP通信,还能进一步探索更复杂的网络应用场景。
Springboot2.0.8集成 netty4 ,使用protobuf作为ping的数据交换,比json更加的小巧,占用数据量更小,可用于任何第三方应用做心跳监控。 已完成功能: - 客户端授权验证(基于protoBuff) - 心跳检测(基于protoBuff) ...
描述中提到,Netty 4.0.45版本已经在公司超过10个项目中得到验证,适合生产环境使用。这表明该版本在内存管理、错误处理和异常恢复等方面具有良好的表现,能够处理各种可能出现的问题,降低系统崩溃的风险。 总的来...
总结起来,这个压缩包为学习和使用Netty提供了一套完整的资源。通过研究源码、阅读API文档和运行示例,开发者可以掌握Netty的精髓,提升网络编程能力,并在实际项目中发挥出Netty的强大性能。无论你是初学者还是经验...
赠送jar包:netty-all-4.0.50.Final.jar; 赠送原API文档:netty-all-4.0.50.Final-javadoc.jar; 赠送源代码:netty-all-4.0.50.Final-sources.jar; 赠送Maven依赖信息文件:netty-all-4.0.50.Final.pom; 包含...
在 Netty 4.0 中,引入了一系列重大改进和变化,旨在提高性能、可维护性和易用性。以下是这些变化的详细说明: 1. **工程结构的改变**: - 包名从 org.jboss.netty 更改为 io.netty,反映了项目的独立性。 - ...
这个"Netty4.0 demo"压缩包包含了一些Netty 4.0版本的应用示例代码,可以帮助我们更好地理解和学习Netty的工作原理以及如何在实际项目中运用它。 1. **Netty简介** Netty 是由JBOSS组织开发的一个开源项目,最初...
赠送jar包:netty-handler-proxy-4.1.68.Final.jar; 赠送原API文档:netty-handler-proxy-4.1.68.Final-javadoc.jar; 赠送源代码:netty-handler-proxy-4.1.68.Final-sources.jar; 赠送Maven依赖信息文件:netty-...
Netty4.0.54英文版API文档,与官网中文档内容一致,方便用户在离线环境下,开发Netty
《Netty进阶之路:跟着案例学Netty》中的案例涵盖了Netty的启动和停止、内存、并发多线程、性能、可靠性、安全等方面,囊括了Netty绝大多数常用的功能及容易让人犯错的地方。在案例的分析过程中,还穿插讲解了Netty...