国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

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

【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即時聊天系統:2.技術簡介之MinaFilter(1)

2019-11-15 00:04:11
字體:
來源:轉載
供稿:網友
【迷你微信】基于MINA、Hibernate、SPRing、Protobuf的即時聊天系統:2.技術簡介之MinaFilter(1)

項目Logo歡迎閱讀我的開源項目《迷你微信》服務器與《迷你微信》客戶端

Filter

filter:過濾器?(不知道是不是這么翻譯,算了知道意思就好了╮(╯▽╰)╭),這種東西在很多語言中都是有的,功能是在某兩層之間插入一層,進行攔截加工處理,這樣可以方便的添加和刪除處理,并且可以添加多層的Fileter。

在Mina的Filter之中,filter是有序的,也就是說,根據你加入filter的方式不同,運行的順序也是不同的,加入方法有點類似于鏈表。對Mina中Filter的詳細使用請參考Mina Filter,在這里,我們只概述兩種Filter的使用:

ProtocolCodecFilter

協議編碼過濾器,這是一個在服務器接收到客戶端數據,或者服務器往客戶端發送數據時使用的一個編碼器(在客戶端的使用亦然),由于網絡的傳輸只能通過字節流或者字符串,所以數據對象的發送接收都必須通過編碼(成字節流)和解碼(成對象)。這時,只要在網絡層添加這么一個ProtocolCodecFilter,便可以隱藏編碼和解碼的實現模塊,而對邏輯層的表現為直接發送對象,接收對象,簡便了使用。廢話不多說,咱們先來看看ProtocolCodecFilter的使用:

首先,在開啟服務器網絡連接的時候添加一個ProtocolCodecFilter (代碼來自開源項目《迷你微信》服務器

    public void init() {        // 自己寫的,負責處理網絡層回調的類        MinaServerHandle minaServerHandle = new MinaServerHandle        // 建立一個NIO(非阻塞)的連接        acceptor = new NioSocketAcceptor();        // 添加 ProtocolCodecFilteracceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MinaEncoder(), new MinaDecoder()));        acceptor.setHandler(minaServerHandle);        try {            // 綁定端口            acceptor.bind(new InetSocketAddress(8081));        } catch (IOException e) {            e.printStackTrace();        }    }
MinaEncoder

大家發現,插入的這個ProtocolCodecFilter中,還有兩個參數:MinaEncoder和MinaDecoder,這兩個類都是帖主自己實現的,請繼續看這兩個類的實現: (代碼來自開源項目《迷你微信》服務器)

    public class MinaEncoder extends ProtocolEncoderAdapter {public final int INT_SIZE = 4        @Overridepublic void encode(Iosession ioSession, Object message, ProtocolEncoderOutput output) throws Exception {byteArrayOutputStream = new ByteArrayOutputStream();byte[] byteArray;if (message.getClass().equals(PacketFromServer.class)) {packetWillSend = (PacketFromServer) message;// 加入數據包byteArray = byteArrayOutputStream.write(packetWillSend.getMessageBoty());int sizeOfAll = byteArrayOutputStream.size() + INT_SIZE;byteArray = byteArrayOutputStream.toByteArray();IoBuffer buffer = IoBuffer.allocate(sizeOfAll);buffer.put(DataTypeTranslater.intToByte(sizeOfAll)); // headerbuffer.put(byteArray); // bodybuffer.flip();output.write(buffer);}}    }

首先,是這個MinaEncoder ,這是在使用ioSession.write(myPacketFromServer)從服務器往客戶端發送數據時調用,需要繼承于ProtocolEncoderAdapter 并覆蓋父類的encode方法。

先解釋一下這個類的用處,當你調用IoSession.write(myPacketFromServer) 的時候,傳入了一個myPacketFromServer的對象,這是一個帖主自己編寫的類PacketFromServer的實例化對象,然而,IO流并不能直接傳輸一個java對象,即便能夠傳輸(序列化,也會導致靈活性降低,因為客戶端就必須使用Java了,所以,在網絡層加上這么一個Filter,攔截住你發送的Java對象,將其轉化為字節流,才能傳輸,而這個類MinaEncoder 便是做的這件事。

使用看看實現,首先,判斷傳進來的是不是PacketFromServer對象,接著,將內容一份一份的取出,轉化成byte數組,放入byteArrayOutputStream中,最后,從byteArrayOutputStream中將之前塞入的全部byte數組全部取出,往IoBuffer中塞入,然后從ProtocolEncoderOutput 寫入通往客戶端的輸出流。其中

  • IoBuffer buffer = IoBuffer.allocate(sizeOfAll); 表示只開sizeOfAll這么大的輸出流,超出后超出的部分將被直接拋棄。
MinaDecoder

接著,輪到MinaDecoder了** (代碼來自開源項目《迷你微信》服務器)**

public class MinaDecoder extends CumulativeProtocolDecoder {@Overrideprotected boolean doDecode(IoSession ioSession, IoBuffer ioBuffer, ProtocolDecoderOutput output) throws Exception {// 如果沒有接收完Size部分(4字節),直接返回falseif (ioBuffer.remaining() < 4)return false;else {// 標記開始位置,如果一條消息沒傳輸完成則返回到這個位置ioBuffer.mark();byteArrayOutputStream = new ByteArrayOutputStream();// 讀取Sizebyte[] bytes = new byte[4];ioBuffer.get(bytes); // 讀取4字節的SizebyteArrayOutputStream.write(bytes);int bodyLength = DataTypeTranslater.bytesToInt(bytes, 0) - DataTypeTranslater.INT_SIZE; // 按小字節序轉int// 如果body沒有接收完整,直接返回falseif (ioBuffer.remaining() < bodyLength) {ioBuffer.reset(); // IoBuffer position回到原來標記的地方return false;} else {byte[] bodyBytes = new byte[bodyLength];ioBuffer.get(bodyBytes);//String body = new String(bodyBytes, "UTF-8");byteArrayOutputStream.write(bodyBytes);// 創建對象NetworkPacket packetFromClient = new NetworkPacket(ioSession, byteArrayOutputStream.toByteArray());output.write(packetFromClient); // 解析出一條消息return true;}}    }

與MinaEncoder 差不多,MinaDecoder 是在接收到數據的時候被調用到,將數據轉化為想要的對象,并交給邏輯層的一個模塊。注意,由于帖主的網絡協議是自己定義的size + objectByte 格式,所以首先接收到的事4byte,將其轉化為int后表明整個包的大小。所以,在客戶端傳遞數據前,要先將整個數據包的大小告訴服務器哦!這是防止粘包和缺包的一種非常有效的方法,這里,插播一下黏包和缺包的解釋:

  • 黏包:由于TCP協議在優化傳輸時,可能將多條小的數據包連接成一個大的數據包一起發送,以此來減少IO次數,提高效率,但這將導致本應該是兩條消息的數據被服務器一次收到,黏在一起,所以叫做粘包。

  • 缺包: 由于TCP協議在優化傳輸時,可能將一個大的數據包分割成幾次發送,導致收到的數據包不全,所以,自行編寫size來保證不會出現缺包問題。

歡迎閱讀我的開源項目《迷你微信》服務器與《迷你微信》客戶端[1]: https://github.com/MrNerverDie/MiniWeChat-Server[2]: https://github.com/MrNerverDie/MiniWeChat-Client


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 双鸭山市| 冷水江市| 泸州市| 建始县| 辽宁省| 土默特左旗| 中西区| 贺兰县| 三门峡市| 宁城县| 神农架林区| 江陵县| 海安县| 博爱县| 丹阳市| 房山区| 武山县| 连州市| 洮南市| 陵水| 韶山市| 霸州市| 海口市| 乌兰察布市| 巴马| 新余市| 隆德县| 泸溪县| 敖汉旗| 呼图壁县| 七台河市| 宁河县| 竹山县| 常州市| 晋中市| 沁阳市| 福州市| 阳东县| 吉水县| 鱼台县| 酉阳|