日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分享套接字数据包序列化与反序列化方法

發(fā)布時(shí)間:2023/12/4 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分享套接字数据包序列化与反序列化方法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

分享套接字?jǐn)?shù)據(jù)包序列化與反序列化方法

簡單說一下,本文不涉及Socket的連接、數(shù)據(jù)接收,只是對數(shù)據(jù)包(byte[])的序列化和反序列化方法的封裝介紹。

本文目錄

  • 本文背景

  • 一般操作

  • 本文操作

  • 總結(jié)

  • 1.本文背景

    經(jīng)常做C/S,客戶端與服務(wù)端通信基本是TCP/UDP通信,套接字用得飛起。

    比如我們有一個(gè)系統(tǒng),這個(gè)系統(tǒng)又分幾個(gè)系統(tǒng)子模塊進(jìn)程:

  • C++服務(wù)端

  • Android 客戶端

  • iOS 客戶端

  • WPF桌面管理端 ......

  • 幾個(gè)模塊之間通過TCP或者UDP通信,數(shù)據(jù)包解析與組裝是常規(guī)操作,我們定義數(shù)據(jù)包格式如下:

    一個(gè)數(shù)據(jù)包包含包頭和包體,定義如下:

    包頭

    序號字段名數(shù)據(jù)類型備注
    1消息標(biāo)識int用于標(biāo)識數(shù)據(jù)包是否合法
    2名稱string當(dāng)前消息名稱,用于標(biāo)識數(shù)據(jù)包類型
    3版本號int當(dāng)前消息版本號,允許程序中消息存在多個(gè)版本,用于版本迭代

    包含這三個(gè)字段:消息標(biāo)識、名稱、版本號,唯一確定消息對象。

    包體

    序號字段名數(shù)據(jù)類型備注
    1字段1數(shù)據(jù)類型字段1
    2字段2數(shù)據(jù)類型字段2

    包體直接定義字段信息,就像定義類屬性一樣。

    另包頭與包體中數(shù)據(jù)類型定義如下:

    數(shù)據(jù)包字段類型定義

    序號數(shù)據(jù)類型備注
    1int4個(gè)字節(jié)的整型值
    2string組成格式:字符串實(shí)際值字節(jié)長度(2個(gè)字節(jié))+字符串實(shí)際值byte
    3char單字節(jié)值
    4列表組成格式:4個(gè)字節(jié)列表長度+列表實(shí)際數(shù)據(jù)值byte
    5字典同上,具體看源碼

    其他數(shù)據(jù)類型類似,復(fù)雜數(shù)據(jù)類型使用4個(gè)字節(jié)的值字節(jié)長度+實(shí)際值byte。

    給一個(gè)測試數(shù)據(jù)包

    序號字段名數(shù)據(jù)類型備注
    1消息標(biāo)識int取值:0x4A534604
    2消息名稱string三國信息,取值:"ThreeCountries"
    3版本號int取值:1
    4編號int給三國一個(gè)編號吧,取值:1
    5國名string取值:"蜀國"
    6皇帝string取值:"劉備"
    7大將個(gè)數(shù)int5
    8大將1編號int取值:1
    9大將1名字string取值:"張飛"
    10大將1備注string取值:"三板斧"
    11大將2編號int取值:2
    12大將2名字string取值:"關(guān)羽"
    13大將2備注string取值:"青龍偃月刀"
    14大將3編號int取值:3
    15大將3名字string取值:"趙云"
    16大將3備注string取值:"很猛的"
    17大將4編號int取值:4
    18大將4名字string取值:"馬超"
    19大將4備注string取值:"強(qiáng)"
    20大將5編號int取值:5
    21大將5名字string取值:"黃忠"
    22大將5備注string取值:"老當(dāng)益壯"

    大致理解下:

    • 前三個(gè)字段是包體:用于標(biāo)識整個(gè)數(shù)據(jù)包,便于包體解析;

    • 后面的包體,簡單說就是三國中的國家信息簡介,前三個(gè)字段為三國中的一個(gè)國家基本信息:編號、國名、皇帝,后面是該國家大將信息列表,每個(gè)大將有編號、名稱、備注等。

    定義數(shù)據(jù)對象

    根據(jù)數(shù)據(jù)包定義,我們可以很快定義類進(jìn)行使用,不管你是C++還是Java。下面是我用C#寫的對應(yīng)類,用于序列化與反序列化使用:

    ///?<summary> ///?三國 ///?</summary> public?class?ThreeCountries {///?<summary>///?獲取或者設(shè)置?ID///?</summary>public?int?ID?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?國名///?</summary>public?string?Name?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?皇帝///?</summary>public?string?Emperor?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?所選課程列表///?</summary>public?List<FamousGeneral>?Courses?{?get;?set;?}public?override?string?ToString(){return?$"三國之一{ID}:{Name}皇帝{Emperor},有?{Courses.Count}名大將";} }///?<summary> ///?三國名將 ///?</summary> public?class?FamousGeneral {///?<summary>///?獲取或者設(shè)置?編號///?</summary>public?int?ID?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?名字///?</summary>public?string?Name?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?描述///?</summary>public?string?Memo?{?get;?set;?}public?override?string?ToString(){return?$"{ID}:{Name}=>{Memo}";} }

    對于上面給的數(shù)據(jù)包你怎么序列化及反序列化?轉(zhuǎn)換成數(shù)據(jù)如下,下節(jié)接著討論

    ThreeCountries?shuKingdom?=?new?ThreeCountries {ID?=?1,Name?=?"蜀國",Emperor?=?"劉備",Courses?=?new?System.Collections.Generic.List<FamousGeneral>{new?FamousGeneral{?ID=1,Name="張飛",Memo="三板斧"},new?FamousGeneral{?ID=2,Name="關(guān)羽",Memo="青龍偃月刀"},new?FamousGeneral{?ID=3,Name="趙云",Memo="很猛的"},new?FamousGeneral{?ID=3,Name="馬超",Memo="強(qiáng)"},new?FamousGeneral{?ID=3,Name="黃忠",Memo="老當(dāng)益壯"},} };

    2. 常規(guī)操作

    序列化

    代碼太繁瑣,我就寫個(gè)不正規(guī)的偽代碼吧

    定義一個(gè)byte數(shù)組; 一、寫包頭 1、寫入4字節(jié)的消息標(biāo)識:0x4A534604 計(jì)算消息對象名稱字符串“ThreeCountries”長度,及轉(zhuǎn)換字符串為byte數(shù)組 2、寫入2字節(jié)的bytes數(shù)組長度,寫入實(shí)際的byte數(shù)組值 3、寫入4字節(jié)的消息版本號 二、寫包體 4、寫入4字節(jié)的大將個(gè)數(shù) 循環(huán)每個(gè)大將信息,依次寫入 5、寫入大將1編號 6、寫入大將1名稱 7、寫入大獎(jiǎng)1備注 8、寫入大將2編號 9、寫入大將3名稱 10、寫入大獎(jiǎng)4備注 ...寫吐了,省略號

    反序列化

    不想寫了,累

    常規(guī)操作

    定義一個(gè)序列化接口,每個(gè)網(wǎng)絡(luò)對象實(shí)現(xiàn)其中的序列化與反序列化接口

    public?interface?ISerializeInterface {byte[]?Serialize<T>(T?t);T?Deserialize<T>(byte[]?arr); }public?class?ThreeCountries?:?ISerializeInterface {public?byte[]?Serialize<T>(T?t){//?將上面的序列化代碼寫在這}T?Deserialize<T>(byte[]?arr){//?將上面的反序列化代碼寫在這,不好意思我沒寫} }

    3. 本文操作

    寫了半天的Demo,文章可能就寫的有點(diǎn)水了,我估計(jì)讀者也不會仔細(xì)看代碼,直接去Github check項(xiàng)目去了,哈哈。

    我還是簡單說說吧,實(shí)現(xiàn)很簡單,定義一些特性,下面紅框里的代碼文件:

    序列化特性及幫助類

    使用很簡單,在上面的數(shù)據(jù)類上加上特性,改動(dòng)不多,看下面代碼:

    ///?<summary> ///?三國 ///?</summary> [NetObject(Name?=?"ThreeCountries",?Version?=?1)] public?class?ThreeCountries {///?<summary>///?獲取或者設(shè)置?ID///?</summary>[NetObjectProperty(ID?=?1)]public?int?ID?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?國名///?</summary>[NetObjectProperty(ID?=?2)]public?string?Name?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?皇帝///?</summary>[NetObjectProperty(ID?=?3)]public?string?Emperor?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?所選課程列表///?</summary>[NetObjectProperty(ID?=?4)]public?List<FamousGeneral>?Courses?{?get;?set;?}public?static?NetObjectAttribute?CurrentObject?=?null;static?ThreeCountries(){CurrentObject?=?NetObjectSerializeHelper.GetAttribute<ThreeCountries,?NetObjectAttribute>(default(ThreeCountries));}public?override?string?ToString(){return?$"三國之一{ID}:{Name}皇帝{Emperor},有?{Courses.Count}名大將";} }///?<summary> ///?三國名將 ///?</summary> public?class?FamousGeneral {///?<summary>///?獲取或者設(shè)置?編號///?</summary>[NetObjectProperty(ID?=?1)]public?int?ID?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?名字///?</summary>[NetObjectProperty(ID?=?2)]public?string?Name?{?get;?set;?}///?<summary>///?獲取或者設(shè)置?描述///?</summary>[NetObjectProperty(ID?=?3)]public?string?Memo?{?get;?set;?}public?override?string?ToString(){return?$"{ID}:{Name}=>{Memo}";} }

    仔細(xì)看的話,只在外層類(ThreeCountries)上加了NetObject特性,和屬性上加了NetObjectProperty特性,分別標(biāo)識消息名稱、版本號及每個(gè)屬性的序列化與反序列化順序即可,類中使用的子對象Courses屬性,也只需要加屬性特性即可,如上。

    下面添加單元測試,并且測試通過:

    單元測試通過

    4. 總結(jié)

    用這套代碼(demo,有所改變,但也差不多),完成了幾個(gè)類似的項(xiàng)目,每次數(shù)據(jù)通信聯(lián)調(diào)、測試問題,C++和java的同事找我時(shí),我就說:

    "你先看你自己數(shù)據(jù)包的序列化和反序列化代碼有沒有問題,我這不會出問題的,完全按數(shù)據(jù)包格式轉(zhuǎn)的。"

    剛開始還在那鬧,后面定位幾次問題后,類似的問題他們就沒再找我了,偷笑中。

    demo寫了半天,還是有點(diǎn)累,源碼:見開源項(xiàng)目TerminalMACS。

    原文鏈接:https://dotnet9.com/16583.html

    歡迎關(guān)注我的微信公眾號:Dotnet9

    Dotnet9微信公眾號

    謝謝您的支持,需要任何資源,只需要在公眾號后臺回復(fù)對應(yīng)數(shù)字即可,切記只回復(fù)“數(shù)字”:

    01:dotnet
    02:java
    03:android
    04:C++
    05:qt
    06:react

    沒有的資源或資源鏈接失效,請給我留言或加我微信,通過百度網(wǎng)盤好友分享。
    另:大部分資源可在我的網(wǎng)站搜索哦:https://dotnet9.com

    總結(jié)

    以上是生活随笔為你收集整理的分享套接字数据包序列化与反序列化方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。