2011-11-04 73 views
1

我創建了2個簡單的控制檯程序和一個簡單的結構。元帥ushort []網絡

M11對象是我們想通過網絡發送的測試對象。

using System.Runtime.InteropServices; 
using System; 

namespace MessageInfo 
{ 

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct M11 
{ 
    /// <summary> 
    /// Message Header 
    /// </summary> 
    public MessageHeader MessageHeader; 

    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I2)] 
    public short[] ArrayOfNumber; 
} 

/// <summary> 
/// Message Header 
/// </summary> 
[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct MessageHeader 
{ 
    public byte mType; 
    public ulong mId; 
} 
} 

而且SimpleSender將封送對象,並通過網絡發送。

static void Main(string[] args) 
    { 

     int m11Size = 0; 
     M11 m11Structure = new M11(); 

     MessageHeader header = new MessageHeader(); 
     header.mType = 0x01; 
     header.mId = Convert.ToUInt64(DateTime.Now.ToString("yyyyMMddHHmmssfff")); 
     m11Size += Marshal.SizeOf(header); 

     m11Structure.MessageHeader = header; 

     short[] arrayOfNumber = new short[5] { 5, 4, 3, 2, 1 }; 
     m11Structure.ArrayOfNumber = arrayOfNumber; 
     m11Size += Marshal.SizeOf(typeof(ushort)) * arrayOfNumber.Length;    

     byte[] m11Bytes = new byte[m11Size]; 
     GCHandle m11Handler = GCHandle.Alloc(m11Bytes, GCHandleType.Pinned); 
     try 
     { 
      IntPtr m11Ptr = m11Handler.AddrOfPinnedObject(); 
      Marshal.StructureToPtr(m11Structure, m11Ptr, false); 
      using (Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) 
      { 
       try 
       { 
        IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.2.110"), 3000); 
        sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); 
        sock.SendTo(m11Bytes, iep); 
       } 
       finally 
       { 
        sock.Close(); 
       } 
      } 

     } 
     catch (Exception ex) { Console.Write(ex.ToString()); } 
     finally { m11Handler.Free(); } 

     Console.ReadLine(); 
    } 

最後但並非最不重要的是,將接收字節並轉換爲對象的接收器。

static void Main(string[] args) 
    { 
     M11 m11Structure = new M11(); 
     using (UdpClient udpClient = new UdpClient(3000)) 
     {     
      try 
      { 
       IPEndPoint ep = new IPEndPoint(IPAddress.Parse("192.168.2.110"), 3000); 
       byte[] m11Bytes = udpClient.Receive(ref ep); 
       GCHandle m11Handler = GCHandle.Alloc(m11Bytes, GCHandleType.Pinned); 
       try 
       { 
        IntPtr m11Ptr = m11Handler.AddrOfPinnedObject(); 
        m11Structure = (M11)Marshal.PtrToStructure(m11Ptr, typeof(M11)); 
        PrintM11Structure(m11Structure); 
       } 
       catch (Exception ex) { Console.WriteLine(ex.ToString()); } 
       finally { m11Handler.Free(); } 

      } 
      finally { udpClient.Close(); } 
     } 

     Console.ReadLine(); 
    } 

的問題是接收器程序總是拋出「System.AccessViolationException:嘗試讀取或寫入受保護的內存」,當它被稱爲Marshal.PtrToStructure。

很少有注意事項: 1.它只適用於MessageHeader。 2.和ushort數組有動態大小。

在此先感謝。

亨利

+0

你的代碼有錯誤的開始。您通過UDP連接發送數據,並且在您首次讀取時,就像整個結構已經到達一樣。爲什麼不使用TCP/IP併爲協議實現細節保存一個噩夢? – Polity

+0

你是否特意綁定**這個特定的**佈局?我問的原因是:有更簡單的方法來實現這一點(仍然非常有效)比編組(編輯:只是測試,我可以使用一種不同的,但更容易的技術,它可以達到20個字節) –

回答

0

至於答案。您無法輕鬆編組具有動態長度的數組。 (雖然您可以使用SafeArray,請參閱Marshal safearray of struct inside struct

如果要通過電線傳輸對象,首先不建議使用編組。使用序列化通過電線發送對象!提示,請查看Marc Gravell的protobuf-net提供的一個非常有效的序列化庫。

您的代碼也存在錯誤。您使用UDP可能是一件痛苦的事情,因爲它不能保證訂單和產能。您必須定義自己的協議來處理所有這些問題,或者僅僅依靠TCP/IP,這本質上提供了防止這些問題的機制。接下來,套接字是基於流的,而不是基於分組的。我真的鼓勵你做一些關於如何使用套接字的google搜索

+0

太棒了,我會看看Marc Gravell的protobuf-net。主要目標是儘可能以最小的尺寸將數據傳輸到其他終端設備。 – Henri