• C#用socket传输类或结构,以及结构和bytes[]互转


    最近有一项目,是和另外一家公司合作,需要接收对方发来的结构消息,然后填充好后发回。

    涉及到利用socket传输和接收struct。

    一般情况下我们只需要利用C#提供的序列化和反序列化即可,将class/struct声明为可序列化的。

    然后利用BinaryFormatter之类的方法进行序列化及反序列化操作~自己可以Google一下:C#序列化

    但是假如对方平台为C++或其它非.NET平台,这样做就不行了。由于不同平台类型之间的差异,

    所以有不小的麻烦。

     先附上C++与C#之间的类型对应关系:

    C++                      输入输出                    C#
    ==================================
    char chr[255]              O               StringBuilder
    KCA_DIR                     I                         int
    LPCSTR                       I                  string
    int                              I                    int
    LPSTR                        O            StringBuilder
    int*                            O               out int
    DWORD                      I                   int
    DWORD*                    O               out int
    BOOL                          I                     bool
    Rc_DBMgr                   I                     IntPtr
    long*                          O               out long

    API与C#的数据类型对应关系表
    API数据类型 类型描述 C#类型 API数据类型 类型描述 C#类型
    WORD 16位无符号整数 ushort CHAR 字符 char
    LONG 32位无符号整数 int DWORDLONG 64位长整数 long
    DWORD 32位无符号整数 uint HDC 设备描述表句柄 int
    HANDLE 句柄,32位整数 int HGDIOBJ GDI对象句柄 int
    UINT 32位无符号整数 uint HINSTANCE 实例句柄 int
    BOOL 32位布尔型整数 bool HWM 窗口句柄 int
    LPSTR 指向字符的32位指针 string HPARAM 32位消息参数 int
    LPCSTR 指向常字符的32位指针 String LPARAM 32位消息参数 int
    BYTE 字节 byte WPARAM 32位消息参数 int

    Wtypes.h 中的非托管类型

    非托管 C 语言类型

    托管类名

    说明

    HANDLE

    void*

    System.IntPtr

    32

    BYTE

    unsigned char

    System.Byte

    8

    SHORT

    short

    System.Int16

    16

    WORD

    unsigned short

    System.UInt16

    16

    INT

    int

    System.Int32

    32

    UINT

    unsigned int

    System.UInt32

    32

    LONG

    long

    System.Int32

    32

    BOOL

    long

    System.Int32

    32

    DWORD

    unsigned long

    System.UInt32

    32

    ULONG

    unsigned long

    System.UInt32

    32

    CHAR

    char

    System.Char

    ANSI 修饰。

    LPSTR

    char*

    System.String System.StringBuilder

    ANSI 修饰。

    LPCSTR

    Const char*

    System.String System.StringBuilder

    ANSI 修饰。

    LPWSTR

    wchar_t*

    System.String System.StringBuilder

    Unicode 修饰。

    LPCWSTR

    Const wchar_t*

    System.String System.StringBuilder

    Unicode 修饰。

    FLOAT

    Float

    System.Single

    32

    DOUBLE

    Double

    System.Double

    64

     需要注意的是非托管的BOOL在C#中对应System.Int32。而在API调用时直接用bool即可。

      

    socket传输的是byte[].所以我们需要把struct转化为byte[]. 有高人为我们提供了如下方法。

     

    //struct转换为byte[]
    static byte[] StructToBytes(object structObj)
    {
    int size = Marshal.SizeOf(structObj);
    IntPtr buffer
    = Marshal.AllocHGlobal(size);
    try
    {
    Marshal.StructureToPtr(structObj, buffer,
    false);
    byte[] bytes = new byte[size];
    Marshal.Copy(buffer, bytes,
    0, size);
    return bytes;
    }
    finally
    {
    Marshal.FreeHGlobal(buffer);
    }

    }
    //byte[]转换为struct
    static object BytesToStruct(byte[] bytes, Type strcutType)
    {
    int size = Marshal.SizeOf(strcutType);
    IntPtr buffer
    = Marshal.AllocHGlobal(size);
    try
    {
    Marshal.Copy(bytes,
    0, buffer, size);
    return Marshal.PtrToStructure(buffer, strcutType);
    }
    finally
    {
    Marshal.FreeHGlobal(buffer);
    }
    }

    一般情况下到此就结束了。但是假如struct里面除了基本数据类型int,long,byte之外,还有 char*.比如:

    typedef struct
    {
       char szStatus[924];	
       char szError[196];
       BYTE bEmergent;
    } CHECK_STATUS_PARAM
    
    

    为了确保数据传输和读取的正确性,应该固定字符串的长度。

    此处就涉及到了:字符串的封送处理。见:http://msdn.microsoft.com/zh-cn/library/s9ts558h(VS.80).aspx

    在不同的情况下我们需要采用不同的封送选项。

    结构中使用的字符串

    字符串是结构的有效成员;但是,StringBuilder 缓冲区在结构中是无效的。下表显示当字符串数据类型被作为字段封送时该类型的封送处理选项。MarshalAsAttribute 属性提供了若干个 UnmanagedType 枚举值,以便将字符串封送到字段。
    枚举类型  非托管格式的说明

    UnmanagedType.BStr  
    具有预设长度和 Unicode 字符的 COM 样式的 BSTR。

    UnmanagedType.LPStr  
    指向 ANSI 字符的空终止数组的指针。

    UnmanagedType.LPTStr 
    指向平台相关的字符的空终止数组的指针。

    UnmanagedType.LPWStr 
    指向 Unicode 字符的空终止数组的指针。

    UnmanagedType.ByValTStr 
    定长的字符数组;数组的类型由包含数组的结构的字符集确定。

      

    项目要求采用ANSI编码,于是C#对应的stuct为:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct CHECK_STATUS_PARAM
    {

    [MarshalAs( UnmanagedType.ByValTStr, SizeConst
    = 924 )]
    public string szStatus;
    [MarshalAs( UnmanagedType.ByValTStr, SizeConst
    = 196 )]
    public string szError;
    public byte bEmergent;
    }

    为了保证正确性,使对象的各个成员在非托管内存中的精确位置被显式控制。我们也可以使用FieldOffsetAttribute指示该字段在类型中的位置。此方法只有在LayoutKind设置为Explicit时使用。 。

    作者:一修先生
             
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    转:五年java人的一点感悟
    6:ZigZag Conversion
    5:Longest Palindromic Substring
    4:Median of Two Sorted Arrays
    3:Longest Substring Without Repeating Characters
    读写分离
    docker swarm部署spring cloud服务
    kubeadm方式安装kubernetes
    《Spring Boot 实战》随记
    https部署
  • 原文地址:https://www.cnblogs.com/1971ruru/p/struct.html
Copyright © 2020-2023  润新知