netty入门学习(4)-LengthFieldPrepender和LengthFieldBasedFrameDecoder
2017-06-03 22:07
459 查看
在netty入门学习(1)中我们曾经提到NIO为了提高效率,默认情况下可以服务端一次write造成客户端多次read,或者服务商多个write但客户端一次全读取过来。模拟演示如下:
改正前:
服务端:
客户端
根据结果可知晓,一次write对应多次read,为了解决这个问题netty提供了两个重要的handler:LengthFieldPrepender和LengthFieldBasedFrameDecoder
在业务处理 handler之前加上这两个handler就可以解决上述的问题了:代码如下
服务端
客户端
改正前:
服务端:
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; public class NioServer { public static void main(String args[]){ //Server服务启动器 ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool())); //设置处理客户端消息和各种消息事件的类(Handler) bootstrap.setPipelineFactory(new ChannelPipelineFactory(){ @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(/*new LengthFieldPrepender(2), new LengthFieldBasedFrameDecoder(64*1024,0,2,0,2),*/ new BusinessHandler()); } }); //绑定8000端口供客户端访问 bootstrap.bind(new InetSocketAddress(8000)); } private static class BusinessHandler extends SimpleChannelHandler{ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage(); System.out.println("Receive:"+buffer.toString(Charset.defaultCharset())); String msg = buffer.toString(Charset.defaultCharset()) + "has been processed!"; ChannelBuffer buffer2 = ChannelBuffers.buffer(msg.length()); buffer2.writeBytes(msg.getBytes()); e.getChannel().write(buffer2); } } }
客户端
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; public class NioClient { public static void main(String args[]){ // Client服务启动器 ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // 设置一个处理服务端消息和各种消息事件的类(Handler) bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(/*new LengthFieldPrepender(2),new LengthFieldBasedFrameDecoder(64*1024,0,2,0,2),*/new RequestHandler()); } }); // 连接到本地的8000端口的服务端 ChannelFuture future = bootstrap.connect(new InetSocketAddress( "127.0.0.1", 8000)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(future.isSuccess()){ StringBuilder builder = new StringBuilder(); builder.append("Request001"); for(int i=0;i<100;i++){ builder.append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); } ChannelBuffer buffer = ChannelBuffers.buffer(builder.toString().length()); buffer.writeBytes(builder.toString().getBytes()); future.getChannel().write(buffer); } } private static class RequestHandler extends SimpleChannelHandler { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage(); System.out.println(buffer.toString(Charset.defaultCharset())); } } }
根据结果可知晓,一次write对应多次read,为了解决这个问题netty提供了两个重要的handler:LengthFieldPrepender和LengthFieldBasedFrameDecoder
在业务处理 handler之前加上这两个handler就可以解决上述的问题了:代码如下
服务端
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; public class NioServer { public static void main(String args[]){ //Server服务启动器 ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),Executors.newCachedThreadPool())); //设置处理客户端消息和各种消息事件的类(Handler) bootstrap.setPipelineFactory(new ChannelPipelineFactory(){ @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new LengthFieldPrepender(2), new LengthFieldBasedFrameDecoder(64*1024,0,2,0,2), new BusinessHandler()); } }); //绑定8000端口供客户端访问 bootstrap.bind(new InetSocketAddress(8000)); } private static class BusinessHandler extends SimpleChannelHandler{ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage(); System.out.println("Receive:"+buffer.toString(Charset.defaultCharset())); String msg = buffer.toString(Charset.defaultCharset()) + "has been processed!"; ChannelBuffer buffer2 = ChannelBuffers.buffer(msg.length()); buffer2.writeBytes(msg.getBytes()); e.getChannel().write(buffer2); } } }
客户端
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; public class NioClient { public static void main(String args[]){ // Client服务启动器 ClientBootstrap bootstrap = new ClientBootstrap( new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // 设置一个处理服务端消息和各种消息事件的类(Handler) bootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new LengthFieldPrepender(2),new LengthFieldBasedFrameDecoder(64*1024,0,2,0,2),new RequestHandler()); } }); // 连接到本地的8000端口的服务端 ChannelFuture future = bootstrap.connect(new InetSocketAddress( "127.0.0.1", 8000)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(future.isSuccess()){ StringBuilder builder = new StringBuilder(); builder.append("Request001"); for(int i=0;i<100;i++){ builder.append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); } ChannelBuffer buffer = ChannelBuffers.buffer(builder.toString().length()); buffer.writeBytes(builder.toString().getBytes()); future.getChannel().write(buffer); } } private static class RequestHandler extends SimpleChannelHandler { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage(); System.out.println(buffer.toString(Charset.defaultCharset())); } } }
相关文章推荐
- netty入门学习(4)-LengthFieldPrepender和LengthFieldBasedFrameDecoder
- Netty学习(四)—LengthFieldBasedFrameDecoder解码器
- Netty学习(六)-LengthFieldBasedFrameDecoder解码器
- [netty]--最通用TCP黏包解决方案:LengthFieldBasedFrameDecoder和LengthFieldPrepender
- 【看完就会】Netty的LengthFieldBasedFrameDecoder的用法详解
- LengthFieldBasedFrameDecoder和LengthFieldPrepender
- 一起学Netty(九)之LengthFieldBasedFrameDecoder
- netty 过长内容分成了多次发送 问题 LengthFieldBasedFrameDecoder使用
- netty LengthFieldBasedFrameDecoder 使用实例
- LengthFieldPrepender和LengthFieldBasedFrameDecoder
- Netty——LengthFieldBasedFrameDecoder
- Netty LengthFieldBasedFrameDecoder使用场景分析
- 一起学Netty(九)之LengthFieldBasedFrameDecoder
- Netty权威指南 第2版学习笔记7——MessagePack编解码及LengthFieldBasedFrameDecoder
- netty——LengthFieldBasedFrameDecoder实例(解决半包)
- Netty的LengthFieldBasedFrameDecoder使用
- Netty LengthFieldBasedFrameDecoder
- Netty LengthFieldBasedFrameDecoder
- Netty LengthFieldBasedFrameDecoder
- 自顶向下深入分析Netty(八)-- LengthFieldBasedFrameDecoder