我创建了2个简单的控制台程序和一个简单的结构。
M11对象是我们想要通过网络发送的测试对象。</ p>
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 :(得分:0)
至于答案。您无法轻松编组具有动态长度的阵列。 (尽管您可以使用SafeArray,请参阅Marshal safearray of struct inside struct)
如果您想通过电线传输物体,则不建议首先使用编组。使用序列化通过线路发送对象!提示,请看Marc Gravell提供的protobuf-net是一个非常有效的序列化库。
您的代码也是错误的。您使用UDP可能是一个痛苦的开始,因为它不保证顺序和可传递性。您要么必须定义自己的协议来处理所有这些,要么只依靠TCP / IP,它本身就提供了防止这些问题的机制。接下来,套接字是基于流的,而不是基于数据包的。我真的鼓励你做一些谷歌搜索如何使用套接字