mina粘包、多包和少包的解決方法

使用過mina的同學(xué)應(yīng)該都遇到到過,在解碼時少包、多包的問題,查閱了很多資料還是迷迷糊糊的,經(jīng)過 不懈努力,終于解決了。原來解決方法是那樣的簡單。廢話少說,請看列子。
問題:我發(fā)送的是xml字符串?dāng)?shù)據(jù),在發(fā)送數(shù)據(jù)后,接收方在解碼的時候可能接到1條,也可能是多條,還 可能是半條或一條半,解決方法就是使用CumulativeProtocolDecoder
首先,在編碼的時候要把前4位設(shè)成標(biāo)志位,標(biāo)志消息內(nèi)容的長度。里面的重點是doDecode的返回值,一 定要繼承CumulativeProtocolDecoder 哦。
請看decode的寫法:

public class AsResponseDecoder extends CumulativeProtocolDecoder {  
    private static Logger LOG = LoggerFactory.getLogger(AsResponseDecoder.class);  
    private final Charset charset;  
      
    public AsResponseDecoder(Charset charset){  
        this.charset = charset;  
    }  
    /** 
     * 這個方法的返回值是重點: 
     * 1、當(dāng)內(nèi)容剛好時,返回false,告知父類接收下一批內(nèi)容 
     * 2、內(nèi)容不夠時需要下一批發(fā)過來的內(nèi)容,此時返回false,這樣父類 
 
CumulativeProtocolDecoder 
     *    會將內(nèi)容放進IoSession中,等下次來數(shù)據(jù)后就自動拼裝再交給本類的doDecode 
     * 3、當(dāng)內(nèi)容多時,返回true,因為需要再將本批數(shù)據(jù)進行讀取,父類會將剩余的數(shù)據(jù)再次推送本 
 
類的doDecode 
     */  
    public boolean doDecode(IoSession session, IoBuffer in,  
            ProtocolDecoderOutput out) throws Exception { 
        CharsetDecoder cd = charset.newDecoder();  
        if(in.remaining() > 0){//有數(shù)據(jù)時,讀取4字節(jié)判斷消息長度  
            byte [] sizeBytes = new byte[4];  
            in.mark();//標(biāo)記當(dāng)前位置,以便reset  
            in.get(sizeBytes);//讀取前4字節(jié)  
                        //NumberUtil是自己寫的一個int轉(zhuǎn)byte[]的一個工具類  
            int size = NumberUtil.byteArrayToInt(sizeBytes);  
            //如果消息內(nèi)容的長度不夠則直接返回true  
            if(size > in.remaining()){//如果消息內(nèi)容不夠,則重置,相當(dāng)于不讀取size  
                in.reset();  
                return false;//接收新數(shù)據(jù),以拼湊成完整數(shù)據(jù)  
            } else{  
                byte[] bytes = new byte[size];   
                in.get(bytes, 0, size);  
                String xmlStr = new String(bytes,"UTF-8");  
                System.out.println("------------"+xmlStr);  
                if(null != xmlStr && xmlStr.length() > 0){  
                    AsResponse resCmd = new AsResponse();  
                    AsXmlPacker.parse(resCmd, xmlStr);  
                    if(resCmd != null){  
                        out.write(resCmd);  
                    }  
                }  
                if(in.remaining() > 0){//如果讀取內(nèi)容后還粘了包,就讓父類再給俺  
  
一次,進行下一次解析  
                    return true;  
                }  
            }  
        }  
        return false;//處理成功,讓父類進行接收下個包  
    }  
}  

下面附上Encode類

public class AsResponseEncoder extends ProtocolEncoderAdapter {  
    private final Charset charset;  
      
    public AsResponseEncoder(Charset charset){  
        this.charset = charset;  
    }  
      
    public void encode(IoSession session, Object message,  
        ProtocolEncoderOutput out) throws Exception {  
        CharsetEncoder ce = charset.newEncoder();  
        IoBuffer buffer = IoBuffer.allocate(100).setAutoExpand(true);  
          
        AsResponse respCmd = (AsResponse) message;  
          
        String xml = AsXmlPacker.pack(respCmd);//將對象轉(zhuǎn)成xml  
        byte[] bytes = xml.getBytes();  
        byte[] sizeBytes = NumberUtil.intToByteArray(bytes.length);  
          
        buffer.put(sizeBytes);//將前4位設(shè)置成數(shù)據(jù)體的字節(jié)長度  
        buffer.put(bytes);//消息內(nèi)容  
        buffer.flip();  
        out.write(buffer);  
    }  
}  

這樣的話,如果數(shù)據(jù)不完整(斷包了)那不就是返回false,繼續(xù)接收下個包的數(shù)據(jù),然后拼裝起來,再次進行doDecode解析,如果還不夠就會繼續(xù)接收,直到出現(xiàn)一個完整的包(非size > in.remaining()),就會執(zhí)行第一個else中的代碼,封裝對象,然后write出去。在這之后再判斷是不是有多余的數(shù)據(jù)(粘包了),如果有,返回true再次繼續(xù)doDecode方法進行對buffer的解析。只要你每次解析的數(shù)據(jù)是按照你所定義的,就不會出現(xiàn)問題。如果出1個字節(jié)的錯誤,那可就全錯了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • 簡介 用簡單的話來定義tcpdump,就是:dump the traffic on a network,根據(jù)使用者...
    保川閱讀 6,076評論 1 13
  • 下午出門了,沒有帶充電器,晚上7點多手機關(guān)機了。 晚上知園老師微課,回到家的時候已經(jīng)晚上8點45,充上電打開手機,...
    黎瀞文閱讀 571評論 0 0
  • 望山 美麗的畫幅里只有紅墻綠瓦,墻角苔草卻無名。 我看見老農(nóng)戴著一頂爛草帽,放眼山頭的...
    處十四閱讀 284評論 2 2
  • 生活,原本是沒有什么顏色,只因那些所見,所感,所悟,才使百無聊賴的日子變得活色生香。這是我用了很久的微博簽名,不知...
    小小小小米77閱讀 557評論 0 2

友情鏈接更多精彩內(nèi)容