答案 0 :(得分:5)
按照@aevitas的回答,我提出了以下解决方案:
public enum SockAddrFamily
{
Inet = 2,
Inet6 = 23
}
[StructLayout(LayoutKind.Sequential)]
public struct SockAddr
{
public ushort Family;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
public byte[] Data;
};
[StructLayout(LayoutKind.Sequential)]
public struct SockAddrIn
{
public ushort Family;
public ushort Port;
public uint Addr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Zero;
}
[StructLayout(LayoutKind.Sequential)]
public struct SockAddrIn6
{
public ushort Family;
public ushort Port;
public uint FlowInfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Addr;
public uint ScopeId;
};
public IPAddress ConvertSockAddrPtrToIPAddress(IntPtr sockAddrPtr)
{
SockAddr sockAddr = (SockAddr)Marshal.PtrToStructure(sockAddrPtr, typeof(SockAddr));
switch ((SockAddrFamily)sockAddr.Family)
{
case SockAddrFamily.Inet:
{
SockAddrIn sockAddrIn = (SockAddrIn)Marshal.PtrToStructure(sockAddrPtr, typeof(SockAddrIn));
return new IPAddress(sockAddrIn.Addr);
}
case SockAddrFamily.Inet6:
{
SockAddrIn6 sockAddrIn6 = (SockAddrIn6)Marshal.PtrToStructure(sockAddrPtr, typeof(SockAddrIn6));
return new IPAddress(sockAddrIn6.Addr);
}
default:
throw new Exception(string.Format("Non-IP address family: {0}", sockAddr.Family));
}
}
我使用IPv4和IPv6地址成功测试了它。
答案 1 :(得分:2)
由于您无法直接Marshal
将sockaddr
类型转换为IPAddress
类型,因此您必须首先将a managed struct out of it编组为:
[StructLayout(LayoutKind.Sequential)]
internal struct sockaddr_in
{
internal EnumLib.ADDRESS_FAMILIES sin_family;
internal ushort sin_port;
internal in_addr sin_addr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] internal byte[] sin_zero;
internal static sockaddr_in FromString(string host, int port)
{
var sockaddr = new sockaddr_in();
var lpAddressLength = Marshal.SizeOf(sockaddr);
WSAStringToAddress(host + ":" + port, EnumLib.ADDRESS_FAMILIES.AF_INET, IntPtr.Zero,
ref sockaddr, ref lpAddressLength);
return sockaddr;
}
}
然后,您可以使用Marshal.PtrToStructure
从sockaddr_in
获取IntPtr
类型,如下所示:
(sockaddr_in) Marshal.PtrToStructure(address, typeof(sockaddr_in));
之后,从您刚检索的数据中创建一个新的IPAddress
对象应该相当简单。
您可以在上面的示例中找到ADDRESS_FAMILIES
中包含的EnumLib
枚举:http://pastie.org/8103489
最初在pinvoke.net上有更多结构成员,如果你对它们感兴趣,只有take a look here,但我认为在这种特定情况下你根本不需要它们。
答案 2 :(得分:0)
您必须在C#中创建相应的结构。使用以下代码(p
是IntPtr
):
(MyStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(p, typeof(MyStruct));
您可以将其“读取”为C#。其余代码很简单,因为您将在sa_data