亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

MINA 網絡黏包處理代碼

2019-11-15 00:45:23
字體:
來源:轉載
供稿:網友
MINA 網絡黏包處理代碼

本文完整代碼,可以瀏覽:

https://github.com/hjj2017/xgame-code_server/blob/master/game_server/src/com/game/gameServer/framework/mina/MsgCumulativeFilter.java

我在網上查閱過的 MINA 黏包處理,一般都是放在 Decoder 中做的。也就是黏包處理和消息解碼放在一起做,顯得比較混亂不好打理。而以下這段代碼,我是把黏包處理放在 Filter 中了。在具體使用時可以這樣:

 1 // 創建 IO 接收器 2 NioSocketAcceptor acceptor = new NioSocketAcceptor(); 3  4 // 獲取責任鏈 5 DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); 6 // 處理網絡粘包 7 chain.addLast("msgCumulative", new MsgCumulativeFilter()); 8  9 // 添加自定義編解碼器10 chain.addLast("msgCodec", new PRotocolCodecFilter(11     new XxxEncoder(),12     new XxxDecoder()13 ));14 15 // 獲取會話配置16 IosessionConfig cfg = acceptor.getSessionConfig();17 18 // 設置緩沖區大小19 cfg.setReadBufferSize(4096);20 // 設置 session 空閑時間21 cfg.setIdleTime(IdleStatus.BOTH_IDLE, 10);22 23 // 設置 IO 句柄24 acceptor.setHandler(new XxxHandler());25 acceptor.setReuseAddress(true);26 27 try {28     // 綁定端口29     acceptor.bind(new InetSocketAddress("127.0.0.1", 4400));30 } catch (Exception ex) {31     // 輸出錯誤日志32     System.error.println(ex);33 }

目前 Netty 框架要比 MINA 流行的多,而且 Netty 對網絡黏包處理也做了很好的處理,不用開發者自己費那么大勁。我也考慮過遷移到 Netty 框架上,不過目前還沒有找到特別充分的理由。閑話不多說了,以下就是黏包處理代碼:

  1 package com.game.gameServer.framework.mina;  2   3 import java.util.concurrent.ConcurrentHashMap;  4   5 import org.apache.mina.core.buffer.IoBuffer;  6 import org.apache.mina.core.filterchain.IoFilterAdapter;  7 import org.apache.mina.core.session.IoSession;  8   9 import com.game.gameServer.framework.FrameworkLog; 10 import com.game.gameServer.msg.SpecialMsgSerialUId; 11 import com.game.part.msg.IoBuffUtil; 12  13 /** 14  * 消息粘包處理 15  *  16  * @author hjj2017 17  * @since 2014/3/17 18  *  19  */ 20 class MsgCumulativeFilter extends IoFilterAdapter { 21     /**  22      * 從客戶端接收的消息估計長度, 23      * {@value} 字節,  24      * 對于從客戶端接收的數據來說, 都是簡單的命令!  25      * 很少超過 {@value}B 26      *  27      */ 28     private static final int DECODE_MSG_LEN = 64; 29     /** 容器 Buff 字典 */ 30     private static final ConcurrentHashMap<Long, IoBuffer> _containerBuffMap = new ConcurrentHashMap<>(); 31  32     @Override 33     public void sessionClosed(NextFilter nextFilter, IoSession sessionObj) throws Exception { 34         if (nextFilter == null ||  35             sessionObj == null) { 36             // 如果參數對象為空,  37             // 則直接退出! 38             FrameworkLog.LOG.error("null nextFilter or sessionObj"); 39             return; 40         } 41  42         // 移除容器 Buff 43         removeContainerBuff(sessionObj); 44         // 向下傳遞 45         super.sessionClosed(nextFilter, sessionObj); 46     } 47  48     @Override 49     public void messageReceived( 50         NextFilter nextFilter, IoSession sessionObj, Object msgObj) throws Exception { 51         if (nextFilter == null ||  52             sessionObj == null) { 53             // 如果參數對象為空,  54             // 則直接退出! 55             FrameworkLog.LOG.error("null nextFilter or sessionObj"); 56             return; 57         } 58  59         // 獲取會話 UId 60         long sessionUId = sessionObj.getId(); 61  62         if (!(msgObj instanceof IoBuffer)) { 63             // 如果消息對象不是 ByteBuff,  64             // 則直接向下傳遞! 65             FrameworkLog.LOG.warn("msgObj is not a IoBuff, sessionUId = " + sessionUId); 66             super.messageReceived(nextFilter, sessionObj, msgObj); 67         } 68  69         // 獲取輸入 Buff 70         IoBuffer inBuff = (IoBuffer)msgObj; 71  72         if (!inBuff.hasRemaining()) { 73             // 如果沒有剩余內容,  74             // 則直接退出! 75             FrameworkLog.LOG.error("inBuff has not remaining, sessionUId = " + sessionUId); 76             return; 77         } else if (inBuff.remaining() <= 8) { 78             // 如果 <= 8 字節,  79             // 那還是執行粘包處理過程吧 ... 80             // 8 字節 = 消息長度 ( Short ) + 消息類型 ( Short ) + 時間戳 ( Int ) 81             // 如果比這個長度都小,  82             // 那肯定不是一條完整消息 ... 83             this.msgRecv_0(nextFilter, sessionObj, inBuff); 84             return; 85         } 86  87         // 獲取消息長度 88         final int msgSize = inBuff.getShort(); 89         inBuff.position(0); 90  91         if (msgSize == inBuff.limit() &&  92             containerBuffIsEmpty(sessionObj)) { 93             //  94             // 如果消息長度和極限值剛好相同,  95             // 并且容器 Buff 中沒有任何內容 ( 即, 上一次消息沒有粘包 ), 96             // 那么直接向下傳遞! 97             //  98             super.messageReceived( 99                 nextFilter, sessionObj, inBuff100             );101         } else {102             // 103             // 如果消息長度和極限值不同, 104             // 則說明是網絡粘包!105             // 這時候跳轉到粘包處理過程 ...106             // 107             this.msgRecv_0(nextFilter, sessionObj, inBuff);108         }109     }110 111     /**112      * 接收連包消息113      * 114      * @param nextFilter115      * @param sessionObj116      * @param inBuff117      * @throws Exception 118      * 119      */120     private void msgRecv_0(121         NextFilter nextFilter, IoSession sessionObj, IoBuffer inBuff) throws Exception {122         if (nextFilter == null || 123             sessionObj == null) {124             // 如果參數對象為空, 125             // 則直接退出!126             FrameworkLog.LOG.error("null nextFilter or sessionObj");127             return;128         }129 130         // 獲取會話 UId131         long sessionUId = sessionObj.getId();132         // 獲取容器 Buff133         IoBuffer containerBuff = getContainerBuff(sessionObj);134 135         // 添加新 Buff 到容器 Buff 的末尾136         IoBuffUtil.append(containerBuff, inBuff);137         // 令 position = 0138         containerBuff.position(0);139 140 //        // 記錄調試信息141 //        FrameworkLog.LOG.debug("/nin = [ " + inBuff.getHexDump() + " ]");142 143         for (int i = 0; ; i++) {144 //            // 記錄調試信息145 //            FrameworkLog.LOG.debug(146 //                "i = " + i 147 //                + "/nco = [ " + containerBuff.getHexDump() + " ]"148 //                + "/nco.pos = " + containerBuff.position() 149 //                + "/nco.lim = " + containerBuff.limit()150 //            );151 152             if (containerBuff.remaining() < 4) {153                 // 154                 // 如果剩余字節數 < 4, 155                 // 這樣根本無法識別出消息類型 msgSerialUId ...156                 // 直接退出!157                 // 在退出前, 158                 // 準備好接收下一次消息!159                 // 160                 IoBuffUtil.readyToNext(containerBuff);161                 return;162             }163 164             // 獲取原始位置165             final int oldPos = containerBuff.position();166             // 獲取消息長度和類型167             final int msgSize = containerBuff.getShort();168             final int msgSerialUId = containerBuff.getShort();169 170 //            // 記錄調試信息171 //            FrameworkLog.LOG.debug(172 //                "i = " + i 173 //                + "/nmsgSize = " + msgSize174 //                + "/nmsgSerialUId = " + msgSerialUId175 //            );176 177             // 還原原始位置178             containerBuff.position(oldPos);179 180             if (msgSerialUId == SpecialMsgSerialUId.CG_Flash_POLICY || 181                 msgSerialUId == SpecialMsgSerialUId.CG_QQ_TGW) {182                 // 183                 // 如果是 Flash 安全策略消息, 184                 // 或者是騰訊網關消息, 185                 // 則嘗試找一下 0 字節的位置 ...186                 // 187                 int pos0 = IoBuffUtil.indexOf(containerBuff, (byte)0);188 189                 if (pos0 <= -1) {190                     // 如果找不到 0 字節的位置, 191                     // 則說明消息還沒接收完, 192                     // 準備接受下次消息并直接退出!193                     IoBuffUtil.readyToNext(containerBuff);194                     return;195                 }196 197                 // 復制 Buff 內容198                 containerBuff.position(0);199                 IoBuffer realBuff = IoBuffUtil.copy(containerBuff, pos0);200 201                 // 更新 Buff 位置202                 final int newPos = containerBuff.position() + pos0;203                 containerBuff.position(newPos);204                 // 壓縮容器 Buff205                 IoBuffUtil.compact(containerBuff);206 207                 // 向下傳遞208                 super.messageReceived(209                     nextFilter, sessionObj, realBuff210                 );211                 continue;212             }213 214             if (msgSize <= 0) {215                 // 216                 // 如果消息長度 <= 0, 217                 // 則直接退出!218                 // 這種情況可能是消息已經亂套了 ...219                 // 還是重新來過吧!220                 // 221                 FrameworkLog.LOG.error("i = " + i + ", msgSize = " + msgSize + ", sessionUId = " + sessionUId);222                 // 將容器 Buff 內容清空223                 containerBuff.position(0);224                 containerBuff.flip();225                 // 壓縮容器 Buff226                 IoBuffUtil.compact(containerBuff);227                 return;228             }229 230             if (containerBuff.remaining() < msgSize) {231                 // 232                 // 如果消息長度不夠, 233                 // 則可能是出現網絡粘包情況了 ...234                 // 直接退出就可以了!235                 // 236                 FrameworkLog.LOG.warn(237                     "i = " + i238                     + ", msgSize = " + msgSize 239                     + ", containerBuff.remaining = " + containerBuff.remaining()240                     + ", sessionUId = " + sessionUId241                 );242 243                 // 準備接受下一次消息244                 IoBuffUtil.readyToNext(containerBuff);245                 return;246             }247 248             // 創建新 Buff 并復制字節內容249             IoBuffer realBuff = IoBuffUtil.copy(containerBuff, msgSize);250 251             if (realBuff == null) {252                 // 253                 // 如果真實的 Buff 為空, 254                 // 則直接退出!255                 // 這種情況可能也是消息亂套了 ...256                 // 記錄一下錯誤信息257                 // 258                 FrameworkLog.LOG.error("i = " + i + ", null realBuff, sessionUId = " + sessionUId);259             } else {260 //                // 記錄調試信息261 //                FrameworkLog.LOG.debug(262 //                    "i = " + i263 //                    + "/nreal = [ " + realBuff.getHexDump() + " ]"264 //                    + "/nreal.pos = " + realBuff.position()265 //                    + "/nreal.lim = " + realBuff.limit()266 //                );267 268                 // 向下傳遞269                 super.messageReceived(270                     nextFilter, sessionObj, realBuff271                 );272             }273 274             // 更新位置275             containerBuff.position(containerBuff.position() + msgSize);276             // 壓縮容器 Buff277             IoBuffUtil.compact(containerBuff);278         }279     }280     281     /**282      * 獲取玩家的 Buff, 如果為空則新建一個!283      * 284      * @param sessionObj285      * @return 286      * 287      */288     private static IoBuffer getContainerBuff(IoSession sessionObj) {289         if (sessionObj == null) {290             // 如果參數對象為空, 291             // 則直接退出!292             return null;293         }294 295         // 獲取會話 UId296         long sessionUId = sessionObj.getId();297         // 獲取容器 Buff298         IoBuffer containerBuff = _containerBuffMap.get(sessionUId);299 300         if (containerBuff == null) {301             // 創建緩存 Buff302             containerBuff = IoBuffer.allocate(DECODE_MSG_LEN);303             containerBuff.setAutoExpand(true);304             containerBuff.setAutoShrink(true);305             containerBuff.position(0);306             containerBuff.flip();307             // 緩存  Buff 對象308             Object oldVal = _containerBuffMap.putIfAbsent(sessionUId, containerBuff);309 310             if (oldVal != null) {311                 FrameworkLog.LOG.warn("exists oldVal");312             }313         }314 315         return containerBuff;316     }317 318     /**319      * 移除容器 Buff320      * 321      * @param sessionObj322      * 323      */324     private static void removeContainerBuff(IoSession sessionObj) {325         if (sessionObj == null) {326             // 如果參數對象為空, 327             // 則直接退出!328             return;329         }330 331         // 獲取會話 UId332         long sessionUId = sessionObj.getId();333         // 獲取容器 Buff334         IoBuffer containerBuff = _containerBuffMap.get(sessionUId);335 336         if (containerBuff != null) {337             // 是否所占資源338             containerBuff.clear();339         }340 341         // 移除玩家的 Buff 對象342         _containerBuffMap.remove(sessionUId);343     }344 345     /**346      * 容器 Buff 為空 ?347      * 348      * @param sessionObj349      * @return 350      * 351      */352     private static boolean containerBuffIsEmpty(IoSession sessionObj) {353         if (sessionObj == null) {354             // 如果參數對象為空, 355             // 則直接退出!356             return false;357         }358 359         // 獲取容器 Buff360         IoBuffer containerBuff = getContainerBuff(sessionObj);361 362         if (containerBuff == null) {363             // 如果容器為空, 364             // 則直接退出!365             FrameworkLog.LOG.error("null containerBuff, sessionUId = " + sessionObj.getId());366             return false;367         } else {368             // 如果當前位置和極限值都為 0, 369             // 則判定為空!370             return (containerBuff.position() == 0 371                  && containerBuff.limit() == 0);372         }373     }374 }


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国内精品视频久久| 美日韩精品视频免费看| 欧美精品在线观看91| 欧美成人免费视频| 欧美诱惑福利视频| 精品福利在线视频| 亚洲va码欧洲m码| 亚洲无亚洲人成网站77777| 亚洲性视频网址| 欧美日韩国产成人| 在线观看欧美日韩国产| 精品美女国产在线| 亚洲最大福利视频网站| 欧美激情免费在线| 福利一区福利二区微拍刺激| 色综合久综合久久综合久鬼88| 成人妇女淫片aaaa视频| 日韩av在线电影网| 国产伦精品免费视频| 欧美大成色www永久网站婷| 亚洲欧美国产一本综合首页| 人人做人人澡人人爽欧美| 国产综合久久久久| 国产亚洲欧美日韩一区二区| 亚洲影院色无极综合| 日韩中文字幕精品视频| 亚洲最大激情中文字幕| 日韩精品免费综合视频在线播放| 日韩欧美在线视频免费观看| www.久久久久| 欧美性猛交xxxx乱大交蜜桃| 国产午夜精品一区二区三区| 日韩精品久久久久久福利| 国产精品成人在线| 亚洲国产高清高潮精品美女| 日韩av手机在线| 欧美日韩性生活视频| 欧美日韩福利在线观看| 中文字幕精品影院| 狠狠色狠狠色综合日日五| www.日韩系列| 精品国产精品三级精品av网址| 国产日韩欧美成人| 欧美做爰性生交视频| 久久噜噜噜精品国产亚洲综合| 中文字幕欧美日韩va免费视频| 麻豆成人在线看| 欧美性生交大片免费| 亚洲国产私拍精品国模在线观看| 国产午夜精品久久久| 久热精品视频在线免费观看| 国产精品美女免费视频| 国内精品视频一区| 97涩涩爰在线观看亚洲| 在线播放精品一区二区三区| 亚洲精品一区久久久久久| 亚洲丝袜一区在线| 亚洲最大的成人网| 欧美视频在线免费| 日本中文字幕久久看| 色樱桃影院亚洲精品影院| 91高清免费在线观看| 欧美日韩高清在线观看| 亚洲人成电影在线播放| 97热在线精品视频在线观看| 日韩电影中文字幕一区| 日韩电影在线观看永久视频免费网站| 亚洲自拍在线观看| 一区二区三区视频在线| 高清欧美一区二区三区| 96精品视频在线| 亚洲国产高清福利视频| 日韩暖暖在线视频| 欧洲成人性视频| 中文字幕亚洲无线码在线一区| 欧美特级www| 欧美一区二区三区精品电影| 亚洲夜晚福利在线观看| 久久97精品久久久久久久不卡| 亚洲国产成人久久综合| 国产精品直播网红| 亚洲精品电影久久久| 久久影院资源站| 欧美激情精品在线| 欧美成人免费全部观看天天性色| 欧美日韩在线视频首页| 成人在线视频网站| 国产区精品在线观看| 伊人激情综合网| 国产www精品| 亚洲精品aⅴ中文字幕乱码| 成人国产精品久久久久久亚洲| 亚洲欧美制服另类日韩| 国产精品丝袜久久久久久不卡| 久久乐国产精品| 久久久久久久999| 国产精品91免费在线| 成人免费高清完整版在线观看| 91在线视频九色| 日韩在线视频观看| 亚洲欧美日韩高清| 国产乱人伦真实精品视频| 国产精品视频男人的天堂| 亚洲一区二区中文字幕| 国产精品一区二区久久国产| 久久色在线播放| www.亚洲男人天堂| 97久久超碰福利国产精品…| 日韩精品在线播放| 国产福利精品av综合导导航| www国产精品视频| 久久精品成人一区二区三区| 亚洲xxxxx| 2020欧美日韩在线视频| 欧美孕妇性xx| 成人网页在线免费观看| 久久精视频免费在线久久完整在线看| 欧美日韩国产影院| 国产一区二区三区网站| 国产精品99久久久久久人| 久久人人看视频| 亚洲欧洲在线观看| 成人黄色av免费在线观看| 亚洲精品一二区| 欧美巨乳美女视频| 永久免费精品影视网站| 日韩精品亚洲视频| 亚洲国产精品va在线观看黑人| 韩国国内大量揄拍精品视频| 久久99热这里只有精品国产| 91黑丝高跟在线| 日韩欧美在线免费| 欧美成年人网站| 91精品在线影院| 一本久久综合亚洲鲁鲁| 亚洲成人精品视频在线观看| 91免费在线视频网站| 久久国产精品免费视频| 久久人人爽人人| 日韩精品极品视频| 91亚洲精品久久久久久久久久久久| 68精品国产免费久久久久久婷婷| 亚洲一区二区三区xxx视频| 亚洲精品久久久久中文字幕欢迎你| 国产在线久久久| 日韩在线一区二区三区免费视频| 中国日韩欧美久久久久久久久| 亚洲欧美日韩中文在线制服| 日韩免费av一区二区| 日本中文字幕成人| 色综合视频一区中文字幕| 中文字幕欧美日韩| 精品成人在线视频| 欧美精品18videos性欧美| 精品视频在线观看日韩| 国产成人自拍视频在线观看| 欧美激情一区二区三区高清视频| 久久69精品久久久久久国产越南| 国产成人精品在线播放| 亚洲精品资源美女情侣酒店| 日韩欧美中文第一页| 日韩欧美中文免费| 日韩视频中文字幕| 国产精品一区二区三区免费视频|