1、netty在進行字節數組傳輸的時候,會出現粘包和分包的情況。當個數據還好,如果數據量很大。並且不間斷的發送給服務器,這個時候就會出現粘包和分包的情況。
2、簡單來說:channelBuffer在接收包的時候,會在當時進行處理,但是當數據量一大,這個時候數據的分隔就不是很明顯了。這個時候會出現數據多了或者少了的情況
3、處理的方式,一般就是編解碼。自己定義數據:數據長度+數據。這種簡單的方式來實現。在server進行解密操作。
4、一般規定的數據格式必須包含:包頭+長度+數據(包頭的目的是用來判斷數據是否是開始的時候)
5、具體的實現過程
a、客戶端進行編碼
package com.troy.application.buffer; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class Client { public static void main(String[] args) { try { SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("localhost",9000)); //需要發送的數據 String message = "hello"; //這里的4代表message的長度所占字節 ByteBuffer byteBuffer = ByteBuffer.allocate(4+message.length()); //設置數據 byteBuffer.putInt(message.length()); byteBuffer.put(message.getBytes()); //寫出數據 socketChannel.write(ByteBuffer.wrap(byteBuffer.array())); } catch (IOException e) { e.printStackTrace(); } } }
b、服務端
package com.troy.application.buffer; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Server { public static void main(String[] args) { //聲明服務類 ServerBootstrap serverBootstrap = new ServerBootstrap(); //設定線程池 ExecutorService boss = Executors.newCachedThreadPool(); ExecutorService work = Executors.newCachedThreadPool(); //設置工廠 serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss,work)); //設置管道流 serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline channelPipeline = Channels.pipeline(); //添加處理方式 channelPipeline.addLast("decode",new PackageDecoder()); channelPipeline.addLast("hello",new HelloHandler()); return channelPipeline; } }); //設置端口 serverBootstrap.bind(new InetSocketAddress(9000)); } }
c、解碼
package com.troy.application.buffer;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
public class PackageDecoder extends FrameDecoder {
@Override
protected Object decode(ChannelHandlerContext channelHandlerContext, Channel channel, ChannelBuffer channelBuffer) throws Exception {
if (channelBuffer.readableBytes() > 4) {
//標記讀取位置
channelBuffer.markReaderIndex();
//讀取數據長度
int n = channelBuffer.readInt();
if (channelBuffer.readableBytes() < n) {
//如果數據長度小於設定的數據,則處於緩存狀態
channelBuffer.resetReaderIndex();
//緩存當前數據,等待數據接入
return null;
}
byte[] bytes = new byte[n];
channelBuffer.readBytes(bytes);
return new String(bytes);
}
//緩存當前數據,等待數據接入
return null;
}
}
d、數據接收處理
package com.troy.application.buffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; public class HelloHandler extends SimpleChannelHandler{ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { System.out.println(e.getMessage()); } }