熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> C編程 >> 正文

C#和C++結構體Socket通信

2013-11-12 23:34:04  來源: C編程 

  最近在用C#做一個項目的時候Socket發送消息的時候遇到了服務端需要接收C++結構體的二進制數據流這個時候就需要用C#仿照C++的結構體做出一個結構來然後將其轉換成二進制流進行發送之後將響應消息的二進制數據流轉換成C#結構

  仿照C++結構體寫出C#的結構來

  using SystemRuntimeInteropServices;

  [Serializable] // 指示可序列化

  [StructLayout(LayoutKindSequential Pack = )] // 按字節對齊

  public struct Operator

  {

  public ushort id;

  [MarshalAs(UnmanagedTypeByValArray SizeConst = )] // 聲明一個字符數組大小為

  public char[] name;

  [MarshalAs(UnmanagedTypeByValArray SizeConst = )]

  public char[] pass;

  public Operator(string user string pass) // 初始化

  {

  thisid = ;

  thisname = userPadRight( \)ToCharArray();

  thispass = passPadRight( \)ToCharArray();

  }

  }

  注意C#與C++數據類型的對應關系

  
C++與C#的數據類型對應關系表 API數據類型 類型描述 C#類型 API數據類型 類型描述 C#類型 WORD 位無符號整數 ushort CHAR 字符 char LONG 位無符號整數 int DWORDLONG 位長整數 long DWORD 位無符號整數 uint HDC 設備描述表句柄 int HANDLE 句柄位整數 int HGDIOBJ GDI對象句柄 int UINT 位無符號整數 uint HINSTANCE 實例句柄 int BOOL 位布爾型整數 bool HWM 窗口句柄 int LPSTR 指向字符的位指針 string HPARAM 位消息參數 int LPCSTR 指向常字符的位指針 String LPARAM 位消息參數 int BYTE 字節 byte WPARAM 位消息參數 int

  整個結構的字節數是bytes

  對應的C++結構體是

  typedef struct

  {

  WORD id;

  CHAR name[];

  CHAR password[];

  }Operator;

  發送的時候先要把結構轉換成字節數組

  using SystemRuntimeInteropServices;

  /// <summary>

  /// 將結構轉換為字節數組

  /// </summary>

  /// <param name=obj>結構對象</param>

  /// <returns>字節數組</returns>

  public byte[] StructToBytes(object obj)

  {

  //得到結構體的大小

  int size = MarshalSizeOf(obj);

  //創建byte數組

  byte[] bytes = new byte[size];

  //分配結構體大小的內存空間

  IntPtr structPtr = MarshalAllocHGlobal(size);

  //將結構體拷到分配好的內存空間

  MarshalStructureToPtr(obj structPtr false);

  //從內存空間拷到byte數組

  MarshalCopy(structPtr bytes size);

  //釋放內存空間

  MarshalFreeHGlobal(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 = MarshalSizeOf(type);

  Log(sizeToString() );

  //byte數組長度小於結構的大小

  if (size > bytesLength)

  {

  //返回空

  return null;

  }

  //分配結構大小的內存空間

  IntPtr structPtr = MarshalAllocHGlobal(size);

  //將byte數組拷到分配好的內存空間

  MarshalCopy(bytes structPtr size);

  //將內存空間轉換為目標結構

  object obj = MarshalPtrToStructure(structPtr type);

  //釋放內存空間

  MarshalFreeHGlobal(structPtr);

  //返回結構

  return obj;

  }

  實際操作

  using SystemCollections;

  using SystemCollectionsGeneric;

  using SystemNet;

  using SystemNetSockets;

  byte[] Message = StructToBytes(new Operator(userpass)); // 將結構轉換成字節數組

  TcpClient socket = new TcpClient();

  socketConnect(ipport);

  NetworkStream ns = SocketGetStream();

  nsWrite(MessageMessageLength); // 發送

  byte[] Recv = new byte[]; // 緩沖

  int NumberOfRecv = ;

  IList<byte> newRecv = new List<byte>();

  nsReadTimeout = ;

  try

  {

  do

  {

  // 接收響應

  NumberOfRecv = nsRead(Recv RecvLength);

  for (int i = ; i < NumberOfRecv; i++)

  newRecvAdd(Recv[i]);

  }

  while (nsDataAvailable);

  byte[] resultRecv = new byte[newRecvCount];

  newRecvCopyTo(resultRecv );

  Operator MyOper = new Operator();

  MyOper = (Operator)BytesToStruct(resultRecv MyOperGetType()); // 將字節數組轉換成結構

  在這裡取值的時候可能會出現只能取到一個字段剩余的取不到的問題怎麼回事我也搞不懂反正我的解決辦法就是按照字節的順序從resultRecv裡分別取出對應的字段的字節數組然後解碼例如

  Operatorname是個字節最後一位是Operatorid是個字節那麼從第位到第位的字節就是Operatorname的內容取出另存為一個數組MyOperNameEncodingDefaultGetString(MyOperName)就是MyOpername的內容

  socketClose();

  nsClose();


From:http://tw.wingwit.com/Article/program/c/201311/11108.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.