摘要:而實際兩者之間的通信使用的是基于的自定義二進制數據幀,對象與數據幀之間需進行轉換。該類實現了編碼解碼方法,故可對消息對象進行編碼或對數據幀進行解碼。該類的靜態方法可通過指定功能消息對象生成相應的回復對象。
本文為該系列的第二篇文章,設計需求為:服務端程序和眾多客戶端程序通過 TCP 協議進行通信,通信雙方需通信的消息種類眾多。上一篇文章詳細描述了該通信協議的二進制數據幀格式以及基本 Java 消息類,假設通信雙方「服務端、客戶端」均由 Netty 框架構建而成,雙方在程序內部使用 Java 消息對象,通信雙方信息交互采用的是自定義二進制幀格式,本文通過一個具體實例,探討指定的 Java 消息對象與其相應的二進制數據幀相互轉換的方法。
1 特定 Java 消息對象通信舉例本小節以一個具體的需求為例,講述該自定義通信協議的工作流程。該需求為:對某一個特定的客戶端進行命名。該需求的具體工作流程描述如下:
服務端需主動向指定的客戶端發送消息,對客戶端設置指定的名稱,客戶端接到指定的消息并驗證合法后,需向服務端反饋消息接受成功的確認回復,服務器接收到該回復后,即可認為對客戶端進行命名的消息發送成功并且名字設置成功,若服務端在指定的時間內未收到回復,需進行重發或者向上層「如管理員或數據庫」反饋該客戶端的異常。
上述過程使用 UML 序列圖演示如下:
由上圖可以直觀地看出:管理員對服務器的操作以及服務器對管理員的反饋均為動作,Server 與 Client 之間的通信以 Java 的視角均通過 Java 消息對象,共需兩個對象:客戶端別名設置對象、客戶端別名設置回復對象。而實際兩者之間的通信使用的是基于 TCP 的自定義二進制數據幀,對象與數據幀之間需進行轉換。
2 該任務所需 Java 消息類的設計上小節所述過程需要兩個 Java 消息類,如下所示:
客戶端別名設置類
/** * 「消息對象」客戶端別名設置 */ public class MsgDeviceName extends BaseMsg { private final String name; public MsgDeviceName(BaseMsgCodec msgCodec, int groupId, int deviceId, String name) { super(msgCodec, groupId, deviceId); this.name = name; } public String getName() { return name; } @Override public String msgDetailToString() { return super.msgDetailToString() + "別名:" + name; } }
客戶端別名設置回復類「直接使用通用回復類」
/** * 「消息對象」通用消息回復 */ public class MsgReplyNormal extends BaseMsg { public MsgReplyNormal(BaseMsgCodec msgCodec, int groupId, int deviceId) { super(msgCodec, groupId, deviceId); } @Override public String msgDetailToString() { return super.msgDetailToString(); } }
客戶端別名設置類相比于基礎消息類,覆寫了消息細節描述方法,優化調試日志的使用體驗。主要改變是,僅僅增加了客戶端別名的引用及其 Get 方法;而對于客戶端別名設置回復,直接使用了通用回復類,減小了設計的復雜度。
該自定義幀協議有一個設計要點:每一個功能性消息類均有相對應的特定回復類。從功能位的角度來看,該兩種類的主幀功能位之間存在如下關系:
消息回復類功能位 - 消息類功能位 = 0x10
即兩類的功能位數值之差以十六進制表示為 0x10。據此設計功能性 Java 消息類后,不需要專門設計對應的回復類,系統會自行使用該通用回復類進行工作。
3 該任務所需消息類編解碼器的設計編碼器可將 Java 消息對象編碼為數據幀,解碼器可講數據幀解碼為指定的 Java 消息對象,上節所述的兩種消息類均需要相對應的編解碼器,如下所示:
3.1 客戶端別名設置編解碼器類該類相比于基礎類,新增了編解碼器的靜態工廠方法,手動傳入功能位及功能文字描述,進而生成包含這些參數的編解碼器。如此設計,使得所有消息的功能位和文字描述均能夠統一管理,降低維護成本。
該類實現了編碼、解碼方法,故可對消息對象進行編碼或對數據幀進行解碼。該類的實現如下所示:
/** * 「消息對象編解碼器」客戶端別名設置 */ public class MsgCodecDeviceName extends BaseMsgCodec { private static MsgCodecDeviceName msgCodec = null; public MsgCodecDeviceName (int majorMsgId, int subMsgId, String detail) { super(majorMsgId, subMsgId, detail); msgCodec = this; } public static MsgDeviceName create(int groupId, int deviceId, String name) { return new MsgDeviceName(msgCodec, groupId, deviceId, name); } @Override public ByteBuf code(BaseMsg msg, ByteBuf buffer) { MsgDeviceName message = (MsgDeviceName) msg; buffer.writeByte(message.getSubMsgId()); byte[] data = KyToArrayUtil.stringToArray(message.getName()); buffer.writeShort(data.length); buffer.writeBytes(data); return buffer; } @Override public MsgDeviceName decode(int groupId, int deviceId, byte[] data) { String name = KyToArrayUtil.arrayToString(data); return create(groupId, deviceId, name); } }3.2 通用回復編解碼器類
該類相比于基礎類,新增了編解碼器的靜態工廠方法,實現了編解碼器,理由與上小節相同。該類的 createByBaseMsg(BaseMsg) 靜態方法可通過指定功能消息對象生成相應的回復對象。該類的實現如下所示:
/** * 「消息對象編解碼器」通用消息回復 */ public class MsgCodecReplyNormal extends BaseMsgCodec { private static MsgCodecReplyNormal msgCodec = null; public MsgCodecReplyNormal(int majorMsgId, int subMsgId, String detail) { super(majorMsgId, subMsgId, detail); msgCodec = this; } /** * 根據收到的消息對象,創建新的通用消息回復對象, * * @param msg 收到的消息對象 * @return 新的通用消息回復對象 */ public static MsgReplyNormal createByBaseMsg(BaseMsg msg) { BaseMsgCodec msgCodec = MsgCodecToolkit.getMsgCodec(msg.getMajorMsgId() + 0x10, msg.getSubMsgId()); if (msgCodec == null) { return null; } return new MsgReplyNormal(msgCodec, msg.getGroupId(), msg.getDeviceId()); } /** * 創建新的通用消息回復對象 * * @param groupId 組號 * @param deviceId 設備號 * @return 生成的通用消息回復對象 */ private MsgReplyNormal create(int groupId, int deviceId) { return new MsgReplyNormal(this, groupId, deviceId); } @Override public ByteBuf code(BaseMsg msg, ByteBuf buffer) { MsgReplyNormal message = (MsgReplyNormal) msg; buffer.writeByte(message.getSubMsgId()); buffer.writeShort(0); return buffer; } @Override public MsgReplyNormal decode(int groupId, int deviceId, byte[] data) { return create(groupId, deviceId); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71070.html
摘要:基本消息對象的設計消息對象的設計主要由兩部分組成特定數據幀對應的特定消息對象。該類包含上節數據幀主幀及子幀的所有公共信息,僅僅未包含子幀中的數據體信息,該需求由基本消息對象的子類實現。 開發工程中,有一個常見的需求:服務端程序和多個客戶端程序通過 TCP 協議進行通信,通信雙方需通信的消息種類眾多,并且客戶端的數量可能有數萬個。為此,雙方需要約定盡可能豐富、靈活的數據幀「數據包」協議,...
摘要:本文仍以該實例為例,探討該自定義通信協議的具體工作流程,以及如何以注冊的形式靈活插拔通信消息對象。進行二進制數據幀的解碼操作時,數據幀中已包含了消息的功能位,據此可獲取相應的編解碼器,而后可以對該數據幀進行解析,生成相應的消息對象。 本文為該系列的第三篇文章,設計需求為:服務端程序和眾多客戶端程序通過 TCP 協議進行通信,通信雙方需通信的消息種類眾多。上一篇文章以一個具體的需求為例,...
項目地址 showImg(https://segmentfault.com/img/remote/1460000019380071); 什么是 Puzzle Puzzle 是基于 Vue 和 Webpack4 實現的一種項目結構;業務模塊可以像拼圖一樣與架構模塊組合,形成不同的系統,而這一切都是可以在生產環境熱插拔的;這意味著你可以隨時向你的系統添加新的功能模塊,甚至改版整個系統,而不需要全量替換...
摘要:比特幣和以太幣屬于一類區塊鏈,我們將其歸類為公共無許可的區塊鏈技術。例如,在單個企業中部署時,或由受信任的權威機構運作,完全拜占庭容錯的共識可能被認為是不必要的,并且對性能和吞吐量造成過度的拖累。 介紹 一般而言,區塊鏈是一個不可變的交易分類賬,維護在一個分布式對等節點網絡中。這些節點通過應用已經由共識協議驗證的交易來維護分類帳的副本,該交易被分組為包括將每個塊綁定到前一個塊的散列的塊...
閱讀 3466·2023-04-25 18:52
閱讀 2479·2021-11-22 15:31
閱讀 1217·2021-10-22 09:54
閱讀 3004·2021-09-29 09:42
閱讀 602·2021-09-26 09:55
閱讀 905·2021-09-13 10:28
閱讀 1092·2019-08-30 15:56
閱讀 2104·2019-08-30 15:55