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

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

【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即時聊天系統:8.自定義傳輸協議

2019-11-15 00:09:23
字體:
來源:轉載
供稿:網友
【迷你微信】基于MINA、Hibernate、SPRing、Protobuf的即時聊天系統:8.自定義傳輸協議

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

前言

在上一篇中,我們講到了《迷你微信》服務器)的主體架構,還講到了如何在現有功能上進行拓展,但是拓展的其中一個關鍵點,就是如何區分客戶端的請求類型(如:登陸?注冊?)?我們將通過對傳輸協議的制定標志位進行檢測來確定客戶端的請求類型,在本項目中,我們使用Protobuf來定義傳輸協議而已,若是您對于Protobuf還不甚了解,可以先學習下【迷你微信】基于MINA、Hibernatye、Spring、Protobuf的即時聊天系統:6.技術簡介之Protobuf。

協議的定義

在[《迷你微信》服務器][1]中,服務器和客戶端所定義的協議為:

  • 1.Size:類型為int,轉化為byte數組后占4個字節。
  • 2.ProtoHead:消息類型(如:登陸?注冊?)類型為ProtoHead,轉化為byte數組后占4個字節。
  • 3.MessageId:一次消息的Id,類型為float,轉化為byte數組后占4個字節。
  • 4.MessageBody:消息主體,類型根據ProtoHead 參數 使用 Protobuf 進行轉化,占用的字節數為 size - sizeOf(size) - sizeOf(ProtoHead) - sizeOf(MessageId),也就是size 轉化為int后的數值減去4 * 3。

注:上述的”消息“指的是客戶端的一次請求或服務器的一次回復或服務器對客戶端的一次推送。

在每一次服務器與客戶端的交流中,都必須遵守這樣的一個協議,否則可能會出現難以估量的異常狀態。可能您會產生懷疑,若是數據包在傳輸的過程中丟了一個包,或者收到數據包的前后順序亂了,會發生什么事?其實,我們用的是TCP的協議,TCP協議是會對數據包進行排序和檢驗丟包的,詳細的介紹可以參考【迷你微信】基于MINA、Hibernatye、Spring、Protobuf的即時聊天系統 :1.技術簡介之Mina連接。

ProtoHead

前面說了,從第五到低8個字節,是ProtoHead,類型也叫ProtoHead,拿這個ProtoHead是什么東西呢?

ProtoHead是使用Protohead編寫的其中一個協議,若是您需要對Protobuf進行了解,請參考【迷你微信】基于MINA、Hibernatye、Spring、Protobuf的即時聊天系統:6.技術簡介之Protobuf。

我們先來看看ProtoHead的定義:

package protocol;option java_package = "protocol";enum ENetworkMessage{    KEEP_ALIVE_SYNC=0;    REGISTER_REQ=1;    REGISTER_RSP=2;    LOGIN_REQ=3;    // 后面還有很多,就不進行展示了。}

先解釋一下:

  • KEEP_ALIVE_SYNC : 心跳包類型,服務器向客戶端發送心跳包以保證對方在線。
  • REGISTER_REQ : 注冊請求類型,這是客戶端向服務器發送的注冊新賬號的請求。
  • REGISTER_RSP : 注冊回復類型,服務器在處理完客戶端的注冊請求后,向客戶端回復結果。
  • LOGIN_REQ : 登陸請求類型,這是客戶端向服務器發送的登陸賬號的請求。

大家可以發現,其實這只是一個枚舉而已,網絡傳輸的時候,我們可以將其轉化為int類型再轉為四個字節。

到此,想必大家已經明白了上一章節中如何區分客戶端請求的類型了,在ClientRequest_Disptcher類中,根據ProtoHead的值,就可以區分出客戶端請求的類型。如果要添加新的功能(服務器與客戶端的交互),則需要在ProtoHead中加入一個新的枚舉類型。

設計新功能

那么如何設計一個新功能的Protobuf呢?

  • 設計新的客戶端與服務器交流的Protobuf 。
  • 在ProtoHead中加入新功能的類型。

現在,加入我們有個功能,是要獲取某個人的詳細信息,那么Protobuf 文件 GetUserInfoMsg.proto 將如此設計:

package protocol;option java_package = "protocol.Msg";import "UserData.proto";message GetUserInfoReq{repeated string targetUserId = 1 ;}message GetUserInfoRsp{enum ResultCode{SUCCESS = 0;//搜索到用戶FAIL = 1;//未搜索到用戶USER_NOT_EXIST = 2;//用戶不存在}required ResultCode resultCode = 1;repeated UserItem userItem = 2;}

大家可以發現,在這里面有兩個消息,一個是客戶端發出的”獲取用戶信息請求“(GetUserInfoReq ),一個是”回復獲取用戶信息請求“(GetUserInfoRsp ),在GetUserInfoReq 中,只有一個參數:目標用戶的Id。而在GetUserInfoRsp 中,首先有一個枚舉的結果,代表獲取信息的結果:搜索到用戶、未搜索到用戶和用戶不存在,接著,是一個UserItem對象,為什么不是詳細數據,而是一個UserItem對象呢?因為UserItem這個對象在很多地方都是要用到的,比如,在”群聊人員表“ 可能是由多個UserItem組成,為了減少重復代碼,所以將其設計成了單獨的一個UserItem。

在此再次強調:消息名不能與文件名相同!

接著,可以在ProtoHead文件中加入新功能的類型枚舉了:

GET_USERINFO_REQ=7;GET_USERINFO_RSP=8;

從此,在客戶端向服務器發送的”獲取用戶信息請求“數據包時,需要將ProtoHead位置設為 GET_USERINFO_REQ ,在服務器回復客戶端結果時要將ProtoHead位置設為 GET_USERINFO_RSP 。

后話

在下一章節,帖主將為大家介紹一下項目內的一些類的詳細設計。

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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 兴和县| 饶平县| 威远县| 利川市| 中阳县| 茶陵县| 平阴县| 达孜县| 屏东市| 洪雅县| 溧水县| 临夏县| 全州县| 广宗县| 永顺县| 上饶市| 甘泉县| 天津市| 同江市| 霍城县| 新龙县| 榆林市| 芜湖市| 繁昌县| 郑州市| 宜兴市| 阿瓦提县| 湖口县| 芒康县| 陇西县| 大邑县| 沽源县| 龙州县| 万源市| 高台县| 西林县| 全州县| 辽中县| 商南县| 大田县| 广宗县|