2012-09-28 19 views
3

我必須開發一個通過TCP Socket從網絡設備讀取數據的服務(C#),並將其轉換爲C#結構。如何將從套接字接收到的字節數組轉換爲C#結構

我基於現有的舊Delphi應用程序正在做所有這些東西,我必須在C#中遷移邏輯。

編輯: 我得到了一個快照從原始數據結構的C-來源:

struct _RequestMsgStruct 
{ 
    UCHAR   request_ver; //In DELPHI it is represented as Byte 
    USHORT   mac_addr[3]; /* MAC Address */ 
    UINT   product_type; //In DELPHI - Cardinal 
    UCHAR   supply_type; //In DELPHI - Byte 
    short   reserved0; //In DELPHI - SmallInt 
    UCHAR   oper_ver[4]; //In DELPHI - CARDINAL !!! 
    USHORT   brd_id; //In DELPHI - WORD 
    unsigned short exp_id1; //In DELPHI - WORD 

    //In DELPHI - string[15]; //Array [0..15] of char; 
    UCHAR   serial_no[16]; /* Serial Number. 16th char have to be NULL */ 
    UCHAR   _name[32]; /* Name */ //Length of payload may vary //In DELPHI - string[31] 

    float   data_avg; //In DELPHI - Single 
    ULONG   key[5]; //In DELPHI - array [0..19] of Byte 
}__attribute__ ((packed)); 

有不同類型的超過200場......它看起來像左右德爾福盒裝記錄:

TREC_DATA = packed record 
     ID   : Byte; 
     MAC_ADDRESS : array [0..5] of Byte; 
     fieldCard  : cardinal; 
     fieldSI  : SmallInt; 
     fieldW  : WORD; 
     SERIAL_NUMBER : string[15]; //Array [0..15] of char; 
     fieldSingle : Single; 
     fieldArrOfB : array [0..19] of Byte; 
    end; 

要移動字節數組在Delphi構建有下一個代碼:

Move(inBytesArr[StartIdx], DelphiStruct, aMsgSize) 

要轉換字符串文件(例如SERIAL_NUMBER)也有這樣的代碼:

var 
    pc: Pchar; 
... 
pc := @inBytesArr[StartIdx + SerialN_Pos_Idx]; 
DelphiStruct.SERIAL_NUMBER := pc; 

我有處理這種轉換的第一次,我不從哪裏開始知道:

  • 如何這種結構轉換爲C#? - 我應該使用LayoutKind.Sequential還是LayoutKind.Explicit,帶或不帶[FieldOffset(N)]屬性? - 我如何在目標c#結構中聲明字節數組:如fixed緩衝區或使用[MarshalAs(UnmanagedType.ByValArray...)]屬性?

  • 哪一個更好的方式來編組輸入字節數組最終C#的結構:使用Marshal.PtrToStructure或GCHandle.Alloc(字節,GCHandleType.Pinned)+ AddrOfPinnedObject

請幫助我,至少從我需要開始的地方獲取起點。

+0

我認爲你給了我們錯誤的結構聲明。你需要給我們一個匹配網絡上的東西。我想這是在C程序中。您將這些對Delphi'string []'類型的引用混淆了。 –

+0

@DavidHeffernan,我得到了原始C結構的快照。 已更新。 – ALZ

+1

你可以接受丹尼斯的回答 –

回答

3

默認情況下,Delphi的打包記錄按單字節邊界對齊字段。
因此,你應該使用這樣的事情:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct TREC_DATA 
{ 
     public byte ID; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 
     public byte[] MAC_ADDRESS; 
     public uint fieldCard; 
     public short fieldSI; 
     public ushort fieldW; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
     public byte[] SERIAL_NUMBER; 
     public float fieldSingle; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] 
     public byte[] fieldArrOfB;  
} 

我不知道(也不能沒有Deplhi現在測試)的唯一的事情,是一個SERIAL_NUMBER場。

更新後:原來,SERIAL_NUMBER只是一個以空字符結尾的字符串。

+0

有沒有辦法讓pinvoke marshaller來處理字符串[15] –

+0

@DavidHeffernan,Dennis,謝謝你的回覆 - 我會檢查它們。我想指定下面的問題: 傳入數據是來自網絡設備的字節數組(通過TCP套接字),設備固件是在UNIX下嵌入C並且我沒有各自的源。我擁有的是舊的Delphi應用程序,我可以將設備通信移動/遷移到新的C#服務,因此,我正在查看實際的Delphi代碼,其中我有一些簡單的內存複製:'Move(inBytesArr [inIdx] ,DelphiStruct,aMsgSize)'。 我假設對於德爾福傳入數據中的字符串已經存在0字節的字節。 – ALZ

+0

@ALZ:這看起來很奇怪......我不相信,一些C編寫的軟件只爲Delphi應用程序構建數據包。也許,有這樣的東西(用C代碼):'''''''''''''' byte [15] serialNumber;'?無論如何,我傾向於說大衛是對的,你應該把這個成員編組爲字節數組。 – Dennis

相關問題