netty之粘包分包的處理


  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());
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM