通过网络元帅 ushort[]
我创建了 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数组具有动态大小。
提前致谢。
亨利
I created 2 simple console program and a simple structure.
M11 Object is the test object that we want to send across network.
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;
}
}
And SimpleSender will Marshal the object and send across the network.
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();
}
Last but not least, the receiver that will receive the bytes and convert to the object.
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();
}
The problem is the receiver program always throw "System.AccessViolationException: Attempted to read or write protected memory" when it called Marshal.PtrToStructure.
Few things to note:
1. It works fine with only MessageHeader.
2. And ushort array has dynamic size.
Thanks in advance.
Henri
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
至于答案。您无法轻松地编组具有动态长度的数组。 (尽管您可以使用 SafeArray,但请参阅 Marshal safearray of struct inside struct )
如果如果您想通过线路传输对象,那么首先不建议使用编组。使用序列化通过网络发送对象!提示,请查看 Marc Gravell 的 protobuf-net,了解一个非常高效的序列化库。
你的代码也有问题。您使用 UDP,一开始可能会很痛苦,因为它不能保证顺序和可交付性。您要么必须定义自己的协议来处理所有这些问题,要么简单地依赖 TCP/IP,它本质上提供了防止这些问题的机制。除此之外,套接字是基于流的,而不是基于数据包的。我真的鼓励你用谷歌搜索一下如何使用套接字
As for the answer. You can't easily marshal an array with dynamic length. (although you can use SafeArray, see Marshal safearray of struct inside struct )
If you want to transfer objects over the wire, than it's not recommended to use marshalling in the first place. Use serialization for sending objects over the wire! Hint, look at protobuf-net by Marc Gravell for a very efficient serialization library.
Your code is faulted as well. You use UDP which can be a pain to begin with since it doesn't guarantee order and deliverability. You either have to define your own protocol which will take care of all of this, or simply rely on TCP/IP which inherently provides mechanisms to prevent these issues. Next to that, sockets are Stream based, not packet based. I really encourage you to do some googling on how to work with sockets