golang二進(jìn)制協(xié)議接口映射


在寫(xiě)服務(wù)器程序時(shí),特別是業(yè)務(wù)向的服務(wù)(比如游戲服務(wù)器),經(jīng)常會(huì)遇到處理許多客戶端協(xié)議的情況松邪,如果是http服務(wù),那么定義好處理接口哨查,剩下的交給web服務(wù)器就可以了逗抑。但是二進(jìn)制協(xié)議就沒(méi)有這么方便了。

通常的自定義二進(jìn)制協(xié)議規(guī)則都是固定長(zhǎng)度消息頭+變長(zhǎng)消息體構(gòu)成,在消息頭中會(huì)有消息長(zhǎng)度邮府,消息id等字段荧关。(基于TCP流式協(xié)議),服務(wù)器接收到客戶端消息后褂傀,首先讀取消息頭忍啤,解析得到消息長(zhǎng)度,再按照指定長(zhǎng)度獲取到完整的消息體的二進(jìn)制數(shù)據(jù)仙辟。

在寫(xiě)具體業(yè)務(wù)邏輯時(shí)同波,需要面臨從網(wǎng)絡(luò)層獲取到的原始數(shù)據(jù),怎么映射到內(nèi)存數(shù)據(jù)結(jié)構(gòu)并調(diào)用相應(yīng)處理接口的問(wèn)題叠国。前面所說(shuō)的二進(jìn)制消息體的格式多種多樣未檩,大家都有自己的做法,這里以protobuf為例粟焊,構(gòu)建服務(wù)器端接收到原始數(shù)據(jù)后冤狡,通過(guò)消息id映射生成對(duì)應(yīng)的protobuf結(jié)構(gòu)體,并調(diào)用處理接口项棠。

golang種有一個(gè)reflect包筒溃,可以對(duì)類型進(jìn)行反射,動(dòng)態(tài)生成相應(yīng)結(jié)構(gòu)體沾乘,具體做法就是怜奖,將protobuf消息結(jié)構(gòu)通過(guò)interface類型和消息id注冊(cè)到一個(gè)自定義map中,在map中保存結(jié)構(gòu)體的類型翅阵,具體如下:

type MessageHandler func(msgid uint16, msg interface{})

type MessageInfo struct {
    msgType    reflect.Type
    msgHandler MessageHandler
}

var (
    msg_map = make(map[uint16]MessageInfo)
)

func RegisterMessage(msgid uint16, msg interface{}, handler MessageHandler) {
    var info MessageInfo
    info.msgType = reflect.TypeOf(msg.(proto.Message))
    info.msgHandler = handler
    msg_map[msgid] = info
}

然后從底層網(wǎng)絡(luò)獲取到原始二進(jìn)制協(xié)議數(shù)據(jù)后歪玲,通過(guò)消息id在map中找到對(duì)應(yīng)的類型信息并動(dòng)態(tài)創(chuàng)建出結(jié)構(gòu)體類型來(lái)解析二進(jìn)制數(shù)據(jù),具體如下:

func HandleRawData(msgid uint16, data []byte) error {
    if info, ok := msg_map[msgid]; ok {
        msg := reflect.New(info.msgType.Elem()).Interface()
        err := proto.Unmarshal(data, msg.(proto.Message))
        if err != nil {
            return err
        }
        info.msgHandler(msgid, msg)
        return err
    }
    return errors.New("not found msgid")
}

這里利用了reflect的反射機(jī)制掷匠,動(dòng)態(tài)獲取類型并創(chuàng)建了protobuf結(jié)構(gòu)體滥崩,然后通過(guò)proto.Umarshal接口解析二進(jìn)制消息體,最后調(diào)用msgHandler進(jìn)行處理讹语。這里的msgHandler是一個(gè)消息處理接口類型钙皮,每個(gè)消息都按照規(guī)范定義自己的處理函數(shù),在程序啟動(dòng)的時(shí)候?qū)⑾⑼缇觯琾rotobuf結(jié)構(gòu)體和處理函數(shù)都統(tǒng)一注冊(cè)短条,如下:

const (
    MsgID_Test1 = iota
    MsgID_Test2
)

func MessageHandler_Test1(msgid uint16, msg interface{}) {
    p := msg.(*pb.MsgTest1)
    fmt.Println("message handler msgid:", msgid, " body:", p)
}

func MessageHandler_Test2(msgid uint16, msg interface{}) {
    p := msg.(*pb.MsgTest2)
    fmt.Println("message handler msgid:", msgid, " body:", p)
}

func RegistMsg() {
    RegisterMessage(MsgID_Test1, &pb.MsgTest1{}, MessageHandler_Test1)
    RegisterMessage(MsgID_Test2, &pb.MsgTest2{}, MessageHandler_Test2)
}

此處注冊(cè)函數(shù)使用的是protobuf消息體的指針類型,所以reflect類型反射的時(shí)候才菠,需要通過(guò)類型的Elem()函數(shù)得到指針的基類型茸时,再動(dòng)態(tài)創(chuàng)建類型。

這樣處理之后赋访,每次新增協(xié)議只需要在RegistMsg函數(shù)里面新加一行即可可都,不需要每個(gè)協(xié)議再單獨(dú)處理二進(jìn)制協(xié)議轉(zhuǎn)換缓待,結(jié)構(gòu)體映射等重復(fù)而繁雜的事情。

代碼在: https://github.com/pertgame/gmsg-framework

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渠牲,一起剝皮案震驚了整個(gè)濱河市旋炒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌签杈,老刑警劉巖国葬,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異芹壕,居然都是意外死亡汇四,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)踢涌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)通孽,“玉大人,你說(shuō)我怎么就攤上這事睁壁”晨啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵潘明,是天一觀的道長(zhǎng)行剂。 經(jīng)常有香客問(wèn)我,道長(zhǎng)钳降,這世上最難降的妖魔是什么厚宰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮遂填,結(jié)果婚禮上铲觉,老公的妹妹穿的比我還像新娘。我一直安慰自己吓坚,他們只是感情好撵幽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著礁击,像睡著了一般盐杂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哆窿,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天链烈,我揣著相機(jī)與錄音,去河邊找鬼更耻。 笑死测垛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秧均。 我是一名探鬼主播食侮,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼目胡!你這毒婦竟也來(lái)了锯七?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤誉己,失蹤者是張志新(化名)和其女友劉穎眉尸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體巨双,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡噪猾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筑累。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袱蜡。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖慢宗,靈堂內(nèi)的尸體忽然破棺而出坪蚁,到底是詐尸還是另有隱情,我是刑警寧澤镜沽,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布敏晤,位于F島的核電站,受9級(jí)特大地震影響缅茉,放射性物質(zhì)發(fā)生泄漏嘴脾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一蔬墩、第九天 我趴在偏房一處隱蔽的房頂上張望统阿。 院中可真熱鬧,春花似錦筹我、人聲如沸扶平。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)结澄。三九已至,卻和暖如春岸夯,著一層夾襖步出監(jiān)牢的瞬間麻献,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工猜扮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勉吻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓旅赢,卻偏偏與公主長(zhǎng)得像齿桃,于是被迫代替她去往敵國(guó)和親惑惶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 10,986評(píng)論 6 13
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理短纵,服務(wù)發(fā)現(xiàn)带污,斷路器,智...
    卡卡羅2017閱讀 134,662評(píng)論 18 139
  • 轉(zhuǎn)自:http://blog.csdn.net/kesonyk/article/details/50924489 ...
    晴天哥_王志閱讀 24,813評(píng)論 2 38
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法香到,類相關(guān)的語(yǔ)法鱼冀,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法悠就,異常的語(yǔ)法千绪,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,639評(píng)論 18 399
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司梗脾,掛了不少荸型,但最終還是拿到小米、百度藐唠、阿里帆疟、京東、新浪宇立、CVTE踪宠、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,253評(píng)論 11 349