c#優雅高效的讀取字節數組——不安全代碼(1)

在開發上位機的經歷中,會有很多需要和下位機交互通信的場景,大多數都會定義一個和硬件的通信協議,最終在上位機代碼中的形式其實就是符合通信協議的字節數組。

場景

在控制一些車輛進行貨物搬運的業務場景下,我們需要即時的獲取小車的狀態數據,並且做出解析,最後進行業務處理。不管與下位機是如何通信的,最終都會讀取到一個字節數組在內存中。
以TCP通訊爲例子,一般會在通訊協議的報文頭中定義報文的長度,從而解決一些通訊問題,如粘包等,最後讀取到正文部分。

如何解析字節數組到類或結構體中

建立與通信協議一致的結構體

比如通訊協議的正文格式定義如下:

id motor_steps speed
1字節 2字節 1字節
  1. id 小車編號
  2. motor_steps 小車行走累計馬達步數
  3. speed 小車當前速度

在代碼中建立對應的結構體

[StructLayout(LayoutKind.Explicit)]
        public struct VehicleStatus
        {
            [FieldOffset(0)] public byte id;
            [FieldOffset(1)] public ushort motor_steps;
            [FieldOffset(3)] public byte speed;
        }
使用不安全代碼將字節數組映射到結構體中
byte[] metaData = new byte[4] { 10, 88, 89, 5 }; //模擬一段報文
            unsafe
            {
                fixed (byte* metaPointer = metaData)
                {
                    VehicleStatus* status = (VehicleStatus*)metaPointer;

                    Console.WriteLine($"小車編號:{status->id}");
                    Console.WriteLine($"小車速度:{status->speed}");
                    Console.WriteLine($"小車馬達步數:{status->motor_steps}");
                }
            }

代碼解釋

StructLayout

表示某個類或者結構體裏的成員的排列方式,這裏我們使用LayoutKind.Explicit精確模式,該模式必須配合FieldOffset屬性一起制定字段的物理內存排列位置。

fixed

用來釘住可移動變量,確保GC在執行期間對不會重新定位或釋放包含對象實例,如果位置變了或者被釋放了,誰還管你的非託管的指針對象呢?這邊字節數組肯定是一個可移動變量了。

參考文檔:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code#fixed-and-moveable-variables

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章