我有一个使用C#编写的BBS门,我想在Linux上工作。 .NET框架的Socket类不支持打开现有的套接字句柄,因此需要为Windows和Linux实现不同的解决方法。
对于Linux,我看了一下Socket.cs文件,看到这发生在DuplicateAndClose()中:
var si = new SocketInformation (); si.Options = (islistening ? SocketInformationOptions.Listening : 0) | (connected ? SocketInformationOptions.Connected : 0) | (blocking ? 0 : SocketInformationOptions.NonBlocking) | (useoverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0); si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)address_family, (int)socket_type, (int)protocol_type, isbound ? 1 : 0, (long)socket); socket = (IntPtr) (-1); return si;
由于我没有从Windows访问Mono.DataConverter,所以我也查看了源代码,并提出了这个问题:
SocketInformation SI = new SocketInformation(); SI.Options = SocketInformationOptions.Connected; SI.ProtocolInformation = new byte[24]; Int32 AF = (Int32)AddressFamily.InterNetwork; Int32 ST = (Int32)SocketType.Stream; Int32 PT = (Int32)ProtocolType.Tcp; Int32 Bound = 0; Int64 Socket = (Int64)ASocketHandle; unsafe { fixed (byte* target = &SI.ProtocolInformation[0]) { uint* source = (uint*)⁡ *((uint*)target) = *source; } fixed (byte* target = &SI.ProtocolInformation[4]) { uint* source = (uint*)&ST; *((uint*)target) = *source; } fixed (byte* target = &SI.ProtocolInformation[8]) { uint* source = (uint*)&PT; *((uint*)target) = *source; } fixed (byte* target = &SI.ProtocolInformation[12]) { uint* source = (uint*)&Bound; *((uint*)target) = *source; } fixed (byte* target = &SI.ProtocolInformation[16]) { long* source = (long*)&Socket; *((long*)target) = *source; } }
所以,现在我已经填充了SocketInformation,我应该能够做到这一点:
Socket S = new Socket(SI); S.Send(new byte[] { 65, 66, 67, 68 });
远程用户应该看到ABCD。 但是,对Send的调用会抛出一个exception,并显示消息“描述符不是套接字”。
所以起初我以为我想做什么是不可能的,但后来我试图调用send():
Socket S = new Socket(SI); send(S.Handle, new byte[] { 65, 66, 67, 68 }, 4, SocketFlags.None);
send()被声明为:
[DllImport("libc")] private extern static int send(IntPtr sock, byte[] buf, int count, SocketFlags flags);
它工作得很好!
所以如果一个pinvoked的调用send()对于描述符来说没问题,那么我在做什么错误的时候让被调用的S.Send()调用失败,说它不是一个套接字描述符? 我假设它与我如何填充SocketInformation有关,但是如果没有别的处理似乎填充正确,因为我可以使用pinvoked发送()…
编辑:进一步深入单声道来源,我可能已经追查到这个问题:
S.Send()将调用Send_internal(),它将调用_wapi_send()。 这是最后调用send()的地方,但是在这之前:
if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); }
所以我猜_wapi_handle_type不会返回WAPI_HANDLE_SOCKET(可能是因为句柄被传入而不是由进程创build的,所以它不知道句柄types),所以这就是我神秘的“描述符不是一个套接字“错误来自于。
猜猜这是一个远射,但有其他人遇到这个问题? 有没有解决scheme,除了完全不受pipe理的套接字I / O?