1

2 つの簡単なコンソール プログラムと簡単な構造を作成しました。

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 配列のサイズは動的です。

前もって感謝します。

アンリ

4

1 に答える 1

0

答えは。動的な長さで配列を簡単にマーシャリングすることはできません。(ただし、SafeArray を使用できます。struct 内の構造体のセーフ配列をマーシャリングするを参照してください)

ワイヤを介してオブジェクトを転送する場合は、最初からマーシャリングを使用することはお勧めしません。シリアル化を使用して、ネットワーク上でオブジェクトを送信してください! ヒント、非常に効率的なシリアル化ライブラリについては、Marc Gravell による protobuf-net を参照してください。

あなたのコードにも障害があります。UDP を使用すると、順序と配信可能性が保証されないため、最初は苦労する可能性があります。これらすべてを処理する独自のプロトコルを定義するか、これらの問題を防ぐメカニズムを本質的に提供する TCP/IP に依存する必要があります。次に、ソケットはストリーム ベースであり、パケット ベースではありません。ソケットの操作方法についてグーグルで検索することをお勧めします

于 2011-11-04T09:14:45.663 に答える