C# 与linux的结构体通讯

 

    很久没写博客了,有时就是坚持不了,现在重新下决定,用博客记录自己的所学,巩固巩固。

    公司项目曾涉及与linux系统通讯的程序,参考了些例子实现了,现在写下了,做个记录供以后查阅,废话不说了,现在开始......

    首先定义C#里的结构体:

  

using System.Runtime.InteropServices;

    [Serializable] // 指示可序列化
    [StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1字节对齐
    public struct MyStruct
    {
         public int id;

         // 声明一个字符数组,大小为20 
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]        
        private char[] name;
        
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
        private char[] password;

        public string Name
        {
              get{   new String(this.name).Trim('\0');}
              set{   this.name = value.PadRight(20, '\0').ToCharArray();}
         }

        public string Password
        {
              get{   new String(this.password).Trim('\0');}
              set{   this.password= value.PadRight(16, '\0').ToCharArray();}
         }


     }

 

注意 set{   this.name = value.PadRight(20, '\0').ToCharArray();}这行代码,value的长度不足20(上面声明的大小:[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] ),要在其后补'\0'.

    接下来,是重点就是将上面的结构体转换成Linux系统可识别的Byte数组:

 

using System.Runtime.InteropServices;     

         /// <summary>
        /// 将结构转换为字节数组
        /// </summary>
        /// <param name="obj">结构对象</param>
        /// <returns>字节数组</returns>
        public byte[] StructToBytes(object obj)
        {
            //得到结构体的大小
            int size = Marshal.SizeOf(obj);
            //创建byte数组
            byte[] bytes = new byte[size];
            //分配结构体大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将结构体拷到分配好的内存空间
            Marshal.StructureToPtr(obj, structPtr, false);
            //从内存空间拷到byte数组
            Marshal.Copy(structPtr, bytes, 0, size);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回byte数组
            return bytes;

       }


        /// <summary>
        /// byte数组转结构
        /// </summary>
        /// <param name="bytes">byte数组</param>
        /// <param name="type">结构类型</param>
        /// <returns>转换后的结构</returns>
        public object BytesToStruct(byte[] bytes, Type type)
        {
            //得到结构的大小
            int size = Marshal.SizeOf(type);
            //byte数组长度小于结构的大小
            if (size > bytes.Length)
            {
                //返回空
                return null;
            }
            //分配结构大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //将内存空间转换为目标结构
            object obj = Marshal.PtrToStructure(structPtr, type);
            //释放内存空间
            Marshal.FreeHGlobal(structPtr);
            //返回结构
            return obj;
        }

 

现在就看看如何将结构体发生给Linux端:

MyStruct mystruct=New MyStruct();
mystruct.id=1;
mystruct.Name="karl";
mystruct.Password="123456";

byte[] senddata=StructToBytes(mystruct);

TcpClient client= new TcpClient((ip,port);
);


NetworkStream ns = client.GetStream();

ns.Write(senddata,0,senddata.Length); // 发送

ns.flush();
client.close();

 

Linux端也要定义一个对应的结构体:

typedef struct myStruct
{
     int id;
    char name[20];
    char password[16];

}  myStructType;

 

接下来linux端怎么接收byte数组转换出结构就不讲了,因为本人只写过一年的单片机程序,也不熟悉Linux端C代码如何写了。貌似有一点要注意的是定义的结构体的大小(字节的总数)最好是8的倍数,好像linux端有字节对齐的问题,曾试过定义的结构不为8的倍数时,linux端的结构大小和实际的不一致。

      到此结束了,本人文笔水平有限,写得有什么不足的,乐意接受大家的建议批评。

 

posted @ 2013-05-11 13:29  碎心炼心  阅读(1296)  评论(0)    收藏  举报