1. 程式人生 > >mina處理斷包和粘包

mina處理斷包和粘包

一.  解碼方法
mina中有個內建類CumulativeProtocolDecoder是專門用來處理斷包和粘包的。該類的api文件中有個實現的例子。
類org.apache.mina.filter.codec.CumulativeProtocolDecoder
public abstract class CumulativeProtocolDecoder extends ProtocolDecoderAdapter {
    private final AttributeKey BUFFER = new AttributeKey(getClass(), "buffer");

    public void decode(IoSession session, IoBuffer in,
            ProtocolDecoderOutput out) throws Exception {
        if (!session.getTransportMetadata().hasFragmentation()) {       //用來判斷是否還有分幀(斷包)
            while (in.hasRemaining()) {
                if (!doDecode(session, in, out)) {
                    break;
                }
            }
            return;
        }
       
      ////處理斷包,省略
      ............................................

    }

    //需要實現的方法

    protected abstract boolean doDecode(IoSession session, IoBuffer in,
            ProtocolDecoderOutput out) throws Exception;
}

CumulativeProtocolDecoder是一個抽象類,必須繼承並實現其doDecode方法,使用者自定義協議的拆分就應該寫在doDecode方法中,下面的類MessageDecoder是一個實現的例子。MessageDecoder解碼網路資料到一種有兩位元組長度頭的自定義訊息協議格式。
/**
 * 斷包和粘包處理,處理後的訊息為一個或多個完整的資料訊息
 * @author blc
 */
public class MessageDecoder extends CumulativeProtocolDecoder {
    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.mina.filter.codec.CumulativeProtocolDecoder#doDecode(org.apache
     * .mina.core.session.IoSession, org.apache.mina.core.buffer.IoBuffer,
     * org.apache.mina.filter.codec.ProtocolDecoderOutput)
     */
    @Override
    protected boolean doDecode(IoSession session, IoBuffer in,
            ProtocolDecoderOutput out) throws Exception {
        
        in.order(ServerConfig.ByteEndian);    //位元組序, ServerConfig.ByteEndian = ByteOrder.LITTLE_ENDIAN
        
        //訊息buf
        IoBuffer buf = IoBuffer.allocate(ServerConfig.MessageMaxByte);   //ServerConfig.MessageMaxByte 最大訊息位元組數
        buf.order(ServerConfig.ByteEndian);
        
        //考慮以下幾種情況:
        //    1. 一個ip包中只包含一個完整訊息
        //    2. 一個ip包中包含一個完整訊息和另一個訊息的一部分
        //    3. 一個ip包中包含一個訊息的一部分
        //    4. 一個ip包中包含兩個完整的資料訊息或更多(迴圈處理在父類的decode中)

        if (in.remaining() > 1) {
            int length = in.getShort(in.position());
if (length < 4) {
                throw new ServerException("Error net message. (Message Length="+length+")");
            }
            if (length > ServerConfig.MessageMaxByte) {
                throw new ServerException("Error net message. Message Length("+length+") > MessageMaxByte("+ServerConfig.MessageMaxByte+")");
            }
            if (length > in.remaining()) return false;
            //複製一個完整訊息
            byte[] bytes = new byte[length];
            in.get(bytes);
            buf.put(bytes);
            
            buf.flip();
            out.write(buf);
            return true;
        } else {
            return false;
        }
    }
}

二.  使用

將上面的解碼器作為一個過濾器配置到mina中即可,在spring中的配置方法如下:
    <!-- 協議過濾器,包括解碼和譯碼 -->
    <bean id="protocolCodecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
        <constructor-arg>
            <bean id="factory" class="server.ClientConnServer.MessageCodecFactory"></bean>
        </constructor-arg>
    </bean>
    <!-- 將協議過濾器配置到mina的過濾鏈中 -->
    <bean id="filterChainBuilder" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
        <property name="filters">
            <map>
                <entry key="protocolCodecFilter" value-ref="protocolCodecFilter" />
            </map>
        </property>
    </bean>
    <!-- 處理器 -->
    <bean id="clientConnHandler" class="server.ClientConnServer.ClientConnHandler" />
    <!-- socket接收器,接收客戶端連線 -->
    <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor" destroy-method="unbind">
        <!--        <property name="defaultLocalAddress" value=":161" />-->
        <property name="handler" ref="clientConnHandler" />
        <property name="reuseAddress" value="true" />
        <property name="filterChainBuilder" ref="filterChainBuilder" />
    </bean>


要配置協議過濾器,必須使用一個ProtocolCodecFactory ,下面是簡單實現
public class MessageCodecFactory implements ProtocolCodecFactory {
    private final MessageEncoder encoder;
    private final MessageDecoder decoder;
    
    public MessageCodecFactory() {
        encoder = new MessageEncoder();
        decoder = new MessageDecoder();
    }

    /* (non-Javadoc)
     * @see org.apache.mina.filter.codec.ProtocolCodecFactory#getDecoder(org.apache.mina.core.session.IoSession)
     */
    @Override
    public ProtocolDecoder getDecoder(IoSession session) throws Exception {
        return decoder;
    }

    /* (non-Javadoc)
     * @see org.apache.mina.filter.codec.ProtocolCodecFactory#getEncoder(org.apache.mina.core.session.IoSession)
     */
    @Override
    public ProtocolEncoder getEncoder(IoSession session) throws Exception {
        return encoder;
    }
}

/**
 * 譯碼器,不做任何事情
 */
public class MessageEncoder extends ProtocolEncoderAdapter {

    /* (non-Javadoc)
     * @see org.apache.mina.filter.codec.ProtocolEncoder#encode(org.apache.mina.core.session.IoSession, java.lang.Object, org.apache.mina.filter.codec.ProtocolEncoderOutput)
     */
    @Override
    public void encode(IoSession session, Object message,
            ProtocolEncoderOutput out) throws Exception {
        //Do nothing
    }

}

相關推薦

mina處理

一.  解碼方法 mina中有個內建類CumulativeProtocolDecoder是專門用來處理斷包和粘包的。該類的api文件中有個實現的例子。 類org.apache.mina.filter.codec.CumulativeProtocolDecoder public abstract clas

TCP協議-滑動視窗、拆

TCP、UDP都可以完成從一端往另一端傳送資料,只是UDP只是負責從傳送端將資料傳送出去就完了,不再管資料是否傳送到接收端是否已經接收到了;而TCP不僅負責傳送資料,還確保資料是否送達,TCP是可靠的,而且它也是可以流控的,管理髮送的速度,不能超過裝置的承受能力。TCP特性1

使用Netty的ReplayingDecoder解決拆問題

概述 在 三篇文章中,筆者介紹了在Netty如何解決拆包和粘包問題,其中自定義解碼器處理半包訊息 裡面介紹的方法是在線上實際用過的,經過了超級大流量的驗證,挺靠譜的。下面再介紹另外一種解決半包問題的方法,雖然我沒實際在線上用過,但是可以當成是一種知識

socket編程 問題的及處理

當前 多少 分包 轉義 保存 長連接 完整 過去 高效 一般在socket處理大數據量傳輸的時候會產生粘包和半包問題,有的時候tcp為了提高效率會緩沖N個包後再一起發出去,這個與緩存和網絡有關系。 粘包 為x.5個包 半包 為0.5個包 由於網絡原因 一次可能會來 0.5/

Socket/TCP、多,

關於Tcp封包 很多朋友已經對此作了不少研究,也花費不少心血編寫了實現程式碼和blog文件。當然也充斥著一些各式的評論,自己看了一下,總結一些心得。 首先我們學習一下這些朋友的心得,他們是: //……………… 當然還有太多,很多東西粘來粘區也不知道到底是誰的原作,J 看這些朋友的blog是我建議親自看一

tcp

    while (1) {       var packLen = _.unpack('packLen', tcpBuffer.slice(0, 2));       len = packLen.len;       // console.log('pack len------:' + len);    

tcp處理方案

隨著智慧硬體越來越流行,很多後端開發人員都有可能接觸到socket程式設計。而很多情況下,伺服器與端上需要保證資料的有序,穩定到達,自然而然就會選擇基於tcp/ip協議的socekt開發。開發過程中,經常會遇到tcp粘包,拆包的問題,本文將從產生原因,和解決方案以及work

關於TCP處理

今日,在程式設計過程中需要在區域網內不同的電腦間傳輸檔案,遇到了TCP協議的粘包和半包現象。經過思考和借鑑,找到了一個比較好的解決方法。因為在傳輸檔案時要先傳輸檔名和檔案大小,然後再傳輸檔案,所以電腦間的應用程式實現了一個小的協議。這個協議需要解碼TCP傳輸的內容。在有粘包

CocoaAsyncSocket + Protobuf 處理問題

 在上一篇文章《iOS之ProtocolBuffer搭建和示例demo》分享環境的搭建, 我們和伺服器進行IM通訊用了github有名的框架CocoaAsynSocket, 然後和伺服器之間的資料媒介是ProtoBuf。然後後面在開發的過程中也碰到了拆包和粘包問題,這方面

Netty中處理TCP

什麼是粘包和拆包 TCP是個”流”協議,流其實就是沒有界限的一串資料。 TCP底層中並不瞭解上層業務資料的具體含義,它會根據TCP緩衝區的實際情況進行包劃分,所以在TCP中就有可能一個完整地包會被TCP拆分成多個包,也有可能吧多個小的包封裝成一個大的資料包傳

處理有關問題的socket分包Java實現

- 處理粘包和半包問題的socket分包Java實現 只知道原理,程式碼實現還不知道怎麼實現?請高手指點,謝謝!高分饋贈!------解決方案-------------------- 一般在socket處理大資料量傳輸的時候會產生粘包和半包問題,有的時候tcp為了提高效

netty的解碼器

exception med 增加 這就是 就會 邊界 ali 空格 封裝 Tcp是一個流的協議,一個完整的包可能會被Tcp拆成多個包進行發送,也可能把一個小的包封裝成一個大的數據包發送,這就是所謂的粘包和拆包問題 粘包、拆包出現的原因: 在流傳輸中出現,UDP不會出現粘包,

SOCKET程式設計流位元組問題readnwriten函式封裝

#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #

Socket:半的一種處理方法

先說下思路: 當出現半包情況時,原本一整段的訊息被分成兩部分或多部分,導致用來判斷訊息是否完整的函式無法判斷,所以這時候就將先到達的內容儲存起來,用於與後到達的內容連線在一起。 當出現粘包情況時,訊息A和訊息B緊密的連線在一起,這就導致處理訊息的函式如果不將訊

問題總結

什麼是TCP粘包半包? 假設客戶端分別傳送了兩個資料包D1和D2給服務端,由於服務端一次讀取到的位元組數是不確定的,故可能存在以下4種情況。 (1)服務端分兩次讀取到了兩個獨立的資料包,分別是D1和D2,沒有粘包和拆包; (2)服務端一次接收到了兩個資料包,D1和D2粘合在一起,被稱為

低級別網路介面-socket的應用現象

套接字的型別        基於檔案型別的套接字家族: AF_UNIX               基於檔案的套接字

Netty學習10-

1 粘包拆包基本概念 TPC是一個面向流的協議。所謂流就是沒有邊界的一串資料,如同河水般連成一片,其中並沒有分界線。TCP底層並不瞭解上層業務資料的具體含義,它會根據TCP緩衝區的具體情況進行包的劃分,所以在業務上認為,一個完整的包可能會被TCP拆成多個包傳送,也有可能

Tcp的原因

最近研究Netty網路程式設計,以前專案中也遇到過資料接收過程中資料質量太差問題,很可能是TCP傳輸過程中問題,特此記錄。 問題產生 一個完整的業務可能會被TCP拆分成多個包進行傳送,也有可能把多個小的包封裝成一個大的資料包傳送,這個就是TCP的拆包和封包問

Unity Socket傳輸 TCP原因以及解決策略

3. 乙太網的payload大於MTU進行IP分片。MTU指:一種通訊協議的某一層上面所能通過的最大資料包大小。如果IP層有一個數據包要傳,而且資料的長度比鏈路層的MTU大,那麼IP層就會進行分片,把資料包分成若干片,讓每一片都不超過MTU。注意,IP分片可以發生在原始傳送端主機上,也可以發生在中間路由器上

java socket編程解決問題

cat exceptio nal end ddr exc gen main socket ##socket 丟包粘包解決方式 采用固定頭部長度(一般為4個字節),包頭保存的是包體的長度 header+body 包頭+包體 思路是:先讀出一個包頭,得到包體的長度