溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

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

發(fā)布時(shí)間:2021-10-26 10:41:51 來源:億速云 閱讀:146 作者:iii 欄目:編程語言

這篇文章主要介紹“套接字?jǐn)?shù)據(jù)包序列化與反序列化方法是什么”,在日常操作中,相信很多人在套接字?jǐn)?shù)據(jù)包序列化與反序列化方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”套接字?jǐn)?shù)據(jù)包序列化與反序列化方法是什么”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

1.本文背景

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

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

  1. C++服務(wù)端

  2. Android 客戶端

  3. iOS 客戶端

  4. WPF桌面管理端 ......

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

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

包頭

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

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

包體

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

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

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

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

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

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

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

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

大致理解下:

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

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

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

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

/// <summary>
/// 三國(guó)
/// </summary>
public class ThreeCountries
{
    /// <summary>
    /// 獲取或者設(shè)置 ID
    /// </summary>
    public int ID { get; set; }

    /// <summary>
    /// 獲取或者設(shè)置 國(guó)名
    /// </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 $"三國(guó)之一{ID}:{Name}皇帝{Emperor},有 {Courses.Count}名大將";
    }
}

/// <summary>
/// 三國(guó)名將
/// </summary>
public class FamousGeneral
{
    /// <summary>
    /// 獲取或者設(shè)置 編號(hào)
    /// </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}";
    }
}

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

ThreeCountries shuKingdom = new ThreeCountries
{
    ID = 1,
    Name = "蜀國(guó)",
    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)識(shí):0x4A534604
計(jì)算消息對(duì)象名稱字符串“ThreeCountries”長(zhǎng)度,及轉(zhuǎn)換字符串為byte數(shù)組
2、寫入2字節(jié)的bytes數(shù)組長(zhǎng)度,寫入實(shí)際的byte數(shù)組值
3、寫入4字節(jié)的消息版本號(hào)
二、寫包體
4、寫入4字節(jié)的大將個(gè)數(shù)
循環(huán)每個(gè)大將信息,依次寫入
5、寫入大將1編號(hào)
6、寫入大將1名稱
7、寫入大獎(jiǎng)1備注
8、寫入大將2編號(hào)
9、寫入大將3名稱
10、寫入大獎(jiǎng)4備注
...寫吐了,省略號(hào)

反序列化

不想寫了,累

常規(guī)操作

定義一個(gè)序列化接口,每個(gè)網(wǎng)絡(luò)對(duì)象實(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ì)讀者也不會(huì)仔細(xì)看代碼,直接去Github check項(xiàng)目去了,哈哈。

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

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

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

/// <summary>
/// 三國(guó)
/// </summary>
[NetObject(Name = "ThreeCountries", Version = 1)]
public class ThreeCountries
{
    /// <summary>
    /// 獲取或者設(shè)置 ID
    /// </summary>
    [NetObjectProperty(ID = 1)]
    public int ID { get; set; }

    /// <summary>
    /// 獲取或者設(shè)置 國(guó)名
    /// </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 $"三國(guó)之一{ID}:{Name}皇帝{Emperor},有 {Courses.Count}名大將";
    }
}

/// <summary>
/// 三國(guó)名將
/// </summary>
public class FamousGeneral
{
    /// <summary>
    /// 獲取或者設(shè)置 編號(hào)
    /// </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)識(shí)消息名稱、版本號(hào)及每個(gè)屬性的序列化與反序列化順序即可,類中使用的子對(duì)象Courses屬性,也只需要加屬性特性即可,如上。

下面添加單元測(cè)試,并且測(cè)試通過:

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

到此,關(guān)于“套接字?jǐn)?shù)據(jù)包序列化與反序列化方法是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI