2011-11-04 21 views
1

私は2つの簡単なコンソールプログラムと簡単な構造を作成しました。Marshal 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(); 
    } 

問題は、受信プログラムは常にスローです:それはMarshal.PtrToStructureを呼び出したときに「System.AccessViolationExceptionは、保護されたメモリを読み書きしようとしました」。

注意すべき事項: 1. MessageHeaderのみで正常に動作します。 2. ushort配列には動的なサイズがあります。

ありがとうございます。

アンリ

+0

あなたのコードは、まず失敗しています。 UDP接続を介してデータを送信し、最初の読み取りでは、構造全体が到着したように動作します。なぜTCP/IPを使用せず、プロトコル実装の詳細の悪夢を避けてみませんか? – Polity

+0

あなたは特にこの**レイアウトに結びついていますか?私が尋ねる理由は:(これは非常に効率的に)これを行うための簡単な方法があります(編集:ちょうどテストされ、20バイト(あなたの19対)得ることができます) –

答えて

0

答えは。動的な長さの配列を簡単に整列化することはできません。 (SafeArrayは使用できますが、Marshal safearray of struct inside structを参照してください)

最初にマーシャリングを使用することは推奨されていません。ワイヤを介してオブジェクトを送信するためにシリアル化を使用してください! Marc Gravellのprotobuf-netを見れば、非常に効率的な直列化ライブラリが得られます。

あなたのコードもフォールトされています。あなたは注文と配送可能性を保証していないので、最初から苦労する可能性のあるUDPを使用します。これらのすべてを処理する独自のプロトコルを定義するか、TCP/IPに依存するだけで、本質的にこれらの問題を回避するメカニズムを提供する必要があります。その次に、ソケットはストリームベースであり、パケットベースではありません。私は本当にあなたがソケットで作業する方法についていくつかのグーグルグーグルを行うことをお勧めします

+0

素晴らしいですが、私はMarc Gravellによってprotobuf-netを調べます。主な目的は、データを可能な限り小さなサイズで他のエンドデバイスに転送することです。 – Henri

関連する問題