如何将IntPtr/Int转换为Socket?

5

我想将message.WParam转换为Socket。

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == Values.MESSAGE_ASYNC)
        {

            switch (m.LParam.ToInt32())
            {
                case Values.FD_READ:
                    WS2.Receive(m.WParam);
                case Values.FD_WRITE: break;
                default: break;
            }

        }
        else
        {
            base.WndProc(ref m);
        }
    }

public class WS2
{
    public static void Receive(IntPtr sock)
    {
        Socket socket = sock;
    }
}

如何将IntrPtr(sock)转换为Socket,以便我可以调用Receive()方法?
2个回答

6

由于Socket类创建和管理其自己的私有套接字句柄,因此您无法这样做。理论上,您可以使用一些邪恶的反射将套接字句柄嵌入到Socket的私有字段中,但这是一种完全的黑客行为,我不会这样做。

如果给定一个有效的套接字句柄,您可以通过P/Invoke调用Win32 recv函数来接收数据,如下所示:

[DllImport("ws2_32.dll")]
extern static int recv([In] IntPtr socketHandle, [In] IntPtr buffer,
  [In] int count, [In] SocketFlags socketFlags);

/// <summary>
/// Receives data from a socket.
/// </summary>
/// <param name="socketHandle">The socket handle.</param>
/// <param name="buffer">The buffer to receive.</param>
/// <param name="offset">The offset within the buffer.</param>
/// <param name="size">The number of bytes to receive.</param>
/// <param name="socketFlags">The socket flags.</param>
/// <exception cref="ArgumentException">If <paramref name="socketHandle"/>
/// is zero.</exception>
/// <exception cref="ArgumentNullException">If <paramref name="buffer"/>
/// is null.</exception>
/// <exception cref="ArgumentOutOfRangeException">If the 
/// <paramref name="offset"/> and <paramref name="size"/> specify a range
/// outside the given buffer.</exception>
public static int Receive(IntPtr socketHandle, byte[] buffer, int offset,
  int size, SocketFlags socketFlags)
{
  if (socketHandle == IntPtr.Zero)
    throw new ArgumentException("socket");
  if (buffer == null)
    throw new ArgumentNullException("buffer");
  if (offset < 0 || offset >= buffer.Length)
    throw new ArgumentOutOfRangeException("offset");
  if (size < 0 || offset + size > buffer.Length)
    throw new ArgumentOutOfRangeException("size");

  unsafe
  {
    fixed (byte* pData = buffer)
    {
      return Recv(socketHandle, new IntPtr(pData + offset),
        size, socketFlags);
    }
  }
}

1

Socket类中没有任何方法可以做到这一点 - 尽管它使用了底层句柄,但没有API来操作它,而且Handle属性是只读的。

你最好通过直接P/Invoke recv并使用IntPtr句柄调用它。

一个Rotor代码快速浏览似乎表明,您可以通过创建一个Socket,关闭它的句柄,然后将其m_handle字段设置为您自己的值。但这需要使用Reflection,如果您的Socket已经连接(因为您刚刚询问了recv),那么您还必须操作Socket的私有状态,这使得该想法变得更加不易接受和脆弱。

在其他语言(C++/Delphi)中,Socket 声明为 Integer。我以为 WParam.ToUint32() 会起作用,但在 C# 中 Socket 不是 int。为什么? - Ivan Prodanov
因为Socket是一个管理自己状态的类 - 它封装了句柄(int)。 - Mark Brackett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接