1. 程式人生 > >Netty自定義協議開發

Netty自定義協議開發

自定義協議格式

%1$8s%2$4s%3$4s%4$8s%5$16s%6$32s%7$8s

類似:AAAAAAAA0001000011001001usernameusernamesession1session1session1session100000023

參考程式碼

package com.phei.netty.codec.custom;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import
io.netty.buffer.Unpooled; import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.buffer.UnpooledDirectByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.CorruptedFrameException; import io.netty.util.ReferenceCountUtil; /** * * @author
Administrator * <pre> * BEFORE DECODE AFTER DECODE * +------+--------+----------------+------+ +----------------+ * | head | Length | body | tail |------->| body | * | int | int | some bytes | int | | some bytes | * +------+--------+----------------+------+ +----------------+ * </pre> */
public class CustomDecoder2 extends ByteToMessageDecoder { private static final ByteBuf HEAD_FLAG = Unpooled.copyInt(0x77aa77aa); private static final int TAIL_FLAG = 0x77ab77ab; private static java.util.concurrent.atomic.AtomicInteger c= new AtomicInteger(1); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { Object o = decode(ctx, in); if (o != null) { out.add(o); System.err.println(c.getAndIncrement()); } } private Object decode(ChannelHandlerContext ctx, ByteBuf in) { in.markReaderIndex(); //查詢包頭位置 int headerOffset = indexOf(in, HEAD_FLAG); if (headerOffset < 0) { //找不到包頭,丟棄多餘位元組 if(in.readableBytes() > 3) in.skipBytes(in.readableBytes()-3); return null; } else { //找到包頭,跳到包頭結束位置 in.skipBytes(headerOffset + 4); } //如發現剩餘位元組不夠4位,回滾指標,等待下次解碼 if (in.readableBytes() < 4) { in.resetReaderIndex(); return null; } //讀取length int bodyLength = in.readInt(); //非法length,丟棄全部位元組,等待下次解碼 if (bodyLength < 0) { return null; } //計算剩餘位元組數(包體 +包尾) int len = bodyLength + 4; //如剩餘位元組不夠,回滾指標,等待下次解碼 if (in.readableBytes() < len) { in.resetReaderIndex(); return null; } //獲取包體 ByteBuf frame = ctx.alloc().buffer(bodyLength); in.readBytes(frame); //讀取包尾 int tail = in.readInt(); //包尾不匹配,則丟棄包體,等待下次解碼 if (tail != TAIL_FLAG) { ReferenceCountUtil.release(frame); return null; } return frame; } private static int indexOf(ByteBuf haystack, ByteBuf needle) { for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i++) { int haystackIndex = i; int needleIndex; for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex++) { if (haystack.getByte(haystackIndex) != needle .getByte(needleIndex)) { break; } else { haystackIndex++; if (haystackIndex == haystack.writerIndex() && needleIndex != needle.capacity() - 1) { return -1; } } } if (needleIndex == needle.capacity()) { // Found the needle from the haystack! return i - haystack.readerIndex(); } } return -1; } public static void main(String[] args) { ByteBuf haystack = Unpooled.buffer(); haystack.writeShort(2); ByteBuf needle = Unpooled.copyInt(0x77aa77aa); // needle.writeInt(0x77aa77aa); System.out.println(indexOf(haystack, needle)); System.out.println(haystack.readerIndex()); } }

我的程式碼

解碼器:

package com.phei.netty.codec.custom;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * CustomDecoder.java 說明
 * 
 * <pre>
 *  BEFORE DECODE                                    AFTER DECODE
 *  
 *  Head                                                    Body
 *  長度80:%1$8s%2$4s%3$4s%4$8s%5$16s%6$32s%7$8s             不定長
 *  (16, 24)命令id,(72, 80)包體長度
 * 
 * </pre>
 * 
 * @author zhengzy
 * @date 2015年12月24日上午10:50:26
 */
public class CustomDecoder extends ByteToMessageDecoder {
    private static int HEADER_SIZE = 80;
    private static int dstStartPos = 72;
    private static int dstStopPos = 80;
    private static ByteBuf buf = Unpooled.buffer();
    private static java.util.concurrent.atomic.AtomicInteger c = new AtomicInteger(1);

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // TODO Auto-generated method stub
        Object o = decode(ctx, in);
        if (o != null) {
            out.add(o);
            System.out.println(c.getAndIncrement());
        }
    }

    private Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {

        //標記讀指標位置,以便可以回滾指標
        in.markReaderIndex();

        // 如發現剩餘位元組不夠80位,回滾指標,等待下次解碼
        if (in.readableBytes() < HEADER_SIZE) {
            in.resetReaderIndex();
            return null;
        }

        //讀取包頭資訊
        in.readBytes(buf, HEADER_SIZE);

        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String headStr = new String(req, "UTF-8");
        int msgLen = Integer.valueOf(headStr.substring(dstStartPos, dstStopPos).trim());

        // 如發現剩餘位元組不夠包體長度,回滾指標,等待下次解碼
        if (in.readableBytes() < msgLen) {
            in.resetReaderIndex();
            return null;
        }

        //讀取包體資訊
        in.readBytes(buf, msgLen);

        ByteBuf frame = ctx.alloc().buffer(HEADER_SIZE + msgLen);
        frame.writeBytes(buf, 0, HEADER_SIZE + msgLen);
        buf.clear();
        return frame;
    }
}

編碼器:

package com.phei.netty.codec.custom;

import com.lytz.pb.Config;
import com.lytz.pb.ProtocolUtils;
import com.lytz.pb.QstockProtocol.LOFMergeSplitReqt;
import com.lytz.pb.QstockProtocol.StockCreateRedeemReqt;
import com.lytz.pb.QstockProtocol.StockOrderReqt;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * CustomEncoder.java 說明
 * 
 * @author zhengzy
 * @date 2015年12月24日下午1:33:24
 */
public class CustomEncoder extends MessageToByteEncoder<Message> {

    private static ByteBuf buf = Unpooled.buffer();
    private static byte[] body = null;
    private static byte[] pro = null;

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        switch (msg.getMsgId()) {
        case Config.ID_S_ORDER_REQT:
            StockOrderReqt stockOrderReqt = (StockOrderReqt) msg.getObject();
            body = stockOrderReqt.toByteArray();
            pro = ProtocolUtils.getProtocol(Config.ID_S_ORDER_REQT, body);
            buf.writeBytes(pro);
            out.writeBytes(buf);
            break;
        case Config.ID_S_LOF_UP_REQT:
            LOFMergeSplitReqt mergeSplitReqt = (LOFMergeSplitReqt) msg.getObject();
            body = mergeSplitReqt.toByteArray();
            pro = ProtocolUtils.getProtocol(Config.ID_S_LOF_UP_REQT, body);
            buf.writeBytes(pro);
            out.writeBytes(buf);
            break;
        case Config.ID_S_LOF_CR_REQT:
            StockCreateRedeemReqt stockCreateRedeemReqt = (StockCreateRedeemReqt) msg.getObject();
            body = stockCreateRedeemReqt.toByteArray();
            pro = ProtocolUtils.getProtocol(Config.ID_S_LOF_CR_REQT, body);
            buf.writeBytes(pro);
            out.writeBytes(buf);
            break;

        default:
            break;
        }
        //清除容器中的資料
        buf.clear();
        body = null;
        pro = null;
    }
}

程式碼說明

    /**
     * 找到needle在haystack中的第一個位置,返回位置,沒有返回-1
     * @param haystack
     * @param needle
     * @return
     */
    private static int indexOf(ByteBuf haystack, ByteBuf needle) {
        for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i++) {
            int haystackIndex = i;
            int needleIndex;
            for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex++) {
                if (haystack.getByte(haystackIndex) != needle
                        .getByte(needleIndex)) {
                    break;
                } else {
                    haystackIndex++;
                    if (haystackIndex == haystack.writerIndex()
                            && needleIndex != needle.capacity() - 1) {
                        return -1;
                    }
                }
            }

            if (needleIndex == needle.capacity()) {
                // Found the needle from the haystack!
                return i - haystack.readerIndex();
            }
        }
        return -1;
    }

測試程式碼:

        String bz = "ABCDEFGH";
        String str = "123ABCDEFGH0001123411101007namenamenamename00000000000000000000000000000000      11";
        ByteBuf buf = Unpooled.buffer();
        buf.writeBytes(str.getBytes());
        ByteBuf bzBuf = Unpooled.buffer();
        bzBuf.writeBytes(bz.getBytes());

        System.out.println(indexOf(buf, Unpooled.copiedBuffer(bz.getBytes())));

參考

相關推薦

Netty定義協議開發

自定義協議格式 %1$8s%2$4s%3$4s%4$8s%5$16s%6$32s%7$8s 類似:AAAAAAAA0001000011001001usernameusernamesession1session1session1session100000023

netty定義協議上傳

客戶端: import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.nett

Netty定義協議解析原理與應用

目前,大家都選擇Netty做為遊戲伺服器框架網路通訊的框架,而且目前也有很多優秀的產品是基於Netty開發的。它的穩定性,易用性和高效率性已得到廣泛的認同。在遊戲伺服器開發中,選擇netty一般就意味著我們要使用長連線來建立與客戶端的通訊,並且是自定義協議,在網路開發中,我們不得不處理斷包,粘包的問題,因為

netty定義協議解碼

繼承ByteToMessageDecoder類複寫decode方法,專案中的一段解碼規則如下: 1、服務端接收報文分為兩種型別,單幀包:head為20位元組,多幀包:head為24位元組。位元組位置:5 2、表示報文體長度欄位為2個位元組,位元組開始位置:18 3、先讀取一

Netty實現定義協議和原始碼分析

本篇 主要講的是自定義協議是如何實現的,以及自定義協議中會出現的問題和Netty是如何支援的。 分為4個部分 |– 粘包 拆包 資料包不全 和解決方案 |– 程式碼實現 |– ByteToMessageDecoder的原始碼分析 |– 過程流程圖 粘包

利用Netty構建定義協議的通訊

在複雜的網路世界中,各種應用之間通訊需要依賴各種各樣的協議,比如:HTTP,Telnet,FTP,SMTP等等。在開發過程中,有時候我們需要構建一些適應自己業務的應用層協議,Netty作為一個非常優秀的網路通訊框架,可以幫助我們完成自定義協議的通訊。一般而言,我們制定的協議需要兩個部分:Header : 協議

【轉】Netty之解決TCP粘包拆包(定義協議)

https://www.cnblogs.com/sidesky/p/6913109.html 1、什麼是粘包/拆包        一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方

netty定義協議(加碼器和解碼器)

1、什麼是粘包/拆包        一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,導致粘包的存在。處理粘包的唯一方法就

Netty之解決TCP粘包拆包(定義協議)

1、什麼是粘包/拆包        一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,導

Netty實現定義協議

       關於協議,使用最為廣泛的是HTTP協議,但是在

netty原始碼解解析(4.0)-20 ChannelHandler: 自己實現一個定義協議的伺服器和客戶端

  本章不會直接分析Netty原始碼,而是通過使用Netty的能力實現一個自定義協議的伺服器和客戶端。通過這樣的實踐,可以更深刻地理解Netty的相關程式碼,同時可以瞭解,在設計實現自定義協議的過程中需要解決的一些關鍵問題。   本週章涉及到的程式碼可以從github上下載: https://git

定義PopupWindow開發

popupwindow近期工作需求,需要做一個彈出窗口,並且裏面包含2個設置項,一個進入詳細設置,一個快捷開關,界面如下: //目前常規的動畫設置,如下幾種mPopWindow.setAnimationStyle(Animation_Toast); 其中,可以設置的動畫值如下:AnimationAnim

通過修改註冊表建立Windows定義協議

height install ict 所有 cee 新建 gpo ogr 編輯 引言 本文主要介紹註冊表的概念與其相關根項的功能,以及瀏覽器如何通過連接調用自定義協議並與客戶端進行數據通信。文中講及如何通過C#程序、手動修改、安裝項目等不同方式對註冊表進行修改。其中通過安

iOS定義協議中的byte使用

自定義的簡單協議一般包括訊息頭部,訊息碼,訊息體,校驗碼和尾部,一個專案裡面用到的頭部和尾部一般都是固定的,訊息碼用來標識是哪一條訊息,校驗碼用來校驗資料完整性 在一些需要相容多端的開發的時候,可能會遇到使用自定義協議,比如與硬體通訊或者使用socket的時候,接受的資料是按約定

【轉載】Chrome使用定義協議開啟本地程式並執行IE開啟網頁

部分內容轉載自: http://blog.sina.com.cn/s/blog_e2b8213a0102wqby.html        專案中遇到某需求:chorme要執行IE並開啟網頁。解決方案之一就是通過自定義協議來實現該需求。     &

定義元件開發九 側邊欄

概述 側邊欄是一種常見的 UI 結構,使用者使用手指左滑或者右滑,可以像抽屜一樣拉出隱藏在屏 幕邊界之外的內容,既能增加 App 的 UI 的內容,又能給使用者帶來更新鮮的使用者體驗,網易新聞、QQ(如圖所示)等主流 App 都有類似的設計。 側邊欄和上一章節講的觸控滑屏有

定義元件開發八 Scroller與平滑滾動

概述 Scroller 譯為“滾動器”,是 ViewGroup 類中原生支援的一個功能。我們經常有這樣的體驗:開啟聯絡人,手指向上滑動,聯絡人列表也會跟著一起滑動,但是,當我們鬆手之後,滑動並不會因此而停止,而是伴隨著一段慣性繼續滑動,最後才慢慢停止。這樣的使用者體驗完全照顧了人的習

定義元件開發定義容器

概述 自定義容器本質上也是一個元件,常見的 LinearLayout、FrameLayout、GridLayout、ScrollView和 RelativeLayout 等等元件都是容器,容器除了有自己的外觀,還能用來容納各種元件,以一種特定的規則規定元件應該在什麼位置、顯示多大。

定義元件開發定義元件

概述 Android SDK 為我們提供了一套完整的元件庫,數量多、功能強,涉及到方方面面,但是,我們依然看到軟體市場上的每個 App 都有自己獨特的東西,絕不是千遍一律的,而且也會和 IOS相互借鑑,這就需要我們對元件進行定製,實現自己獨樹一幟的使用者體驗和介面風格。自定義元件到底

定義元件開發五 陰影、 漸變和點陣圖運算

介紹陰影、漸變和點陣圖運算等技術 陰影只是一個狹義的說法,實際上也包括髮光等效果;Android 也提供了強大的漸變功能,漸變能為物體帶來更真實的質感,比如可以用漸變繪製一顆五子棋或一根金屬圓棒;點陣圖運算就更有趣了,Android 為 Bitmap 的運算提供了多達16 種運算方法,