如何将 SOCKET (HANDLE) 从非托管 C 程序传递到 .NET 子进程?
How to pass a SOCKET (HANDLE) from unmanaged C program to .NET child process?
我们有一个用 C 编写的 Windows 服务 (WS)。WS 在端口上侦听传入请求。其中一个请求是启动子进程并将 SOCKET 传递给它,以便请求应用程序服务器 (RAS) 之后继续与子进程对话。子进程可执行文件 (CPE) 也是用 C 编写的。
这是 WS 的(简化)代码:
...
HANDLE curr_channel // is the SOCKET our WS got from accepting an incoming connection attempt
HANDLE process_h = GetCurrentProcess();
HANDLE new_channel;
DuplicateHandle(process_h, curr_channel, process_h, &new_channel, 0, TRUE, DUPLICATE_SAME_ACCESS); // note that bInheritHandles is set to TRUE (1)
char command_line[2048];
sprintf(command_line, "<path to executable to be started as child process> %Iu", (unsigned __int64)new_channel);
PROCESS_INFORMATION process_info;
memset(&process_info, 0, sizeof(PROCESS_INFORMATION));
STARTUPINFO startup;
memset(&startup, 0, sizeof(STARTUPINFO));
startup.cb = sizeof(STARTUPINFO);
CreateProcess(NULL, command_line, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &process_info); // note that bInheritHandles is set to TRUE (1)
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
CloseHandle(new_channel);
...
这是 CPE 的(简化)代码:
...
int pipeFd = atoi(argv[1]);
char *outBuf = ... // the message to be sent to the RAS as this is waiting for a (synchronous) response
int size = ... // length of this message
int cnt = send(pipeFd, outBuf, size, 0);
...
多年来,这一切都非常有效。现在我们想用一个用C#编写的程序来代替CPE,我们称之为CPE.NET。 WS 应该保持原样(用 C 编写)。
这是 CPE.NET 的(简化)代码:
class Program {
[DllImport("ws2_32.dll")]
extern static int send([In] IntPtr socketHandle, [In] IntPtr buffer, [In] int count, [In] SocketFlags socketFlags);
public static int Send(IntPtr socketHandle, byte[] buffer, int offset, int size, SocketFlags socketFlags) {
unsafe {
fixed (byte* pData = buffer) {
return send(socketHandle, new IntPtr(pData + offset), size, socketFlags);
}
}
}
static void Main(string[] args) {
int socketHandle;
if (!int.TryParse(args[1], out socketHandle))
return;
byte[] data = new byte[] { ... }; // the message to be sent to the RAS as this is waiting for a (synchronous) response
int retSendWithDotNet = Send(new IntPtr(socketHandle), data, 0, data.Length, 0);
...
现在的问题是 retSendWithDotNet 总是 -1。知道为什么会这样吗?
谢谢,
迈克尔
"You need to call WSAGetLastError to get more information. My guess is that sockets are not initialized (see WSAStartup)."
简单但有效。调用 WSAStartup() 就成功了。
非常感谢。
我们有一个用 C 编写的 Windows 服务 (WS)。WS 在端口上侦听传入请求。其中一个请求是启动子进程并将 SOCKET 传递给它,以便请求应用程序服务器 (RAS) 之后继续与子进程对话。子进程可执行文件 (CPE) 也是用 C 编写的。
这是 WS 的(简化)代码:
...
HANDLE curr_channel // is the SOCKET our WS got from accepting an incoming connection attempt
HANDLE process_h = GetCurrentProcess();
HANDLE new_channel;
DuplicateHandle(process_h, curr_channel, process_h, &new_channel, 0, TRUE, DUPLICATE_SAME_ACCESS); // note that bInheritHandles is set to TRUE (1)
char command_line[2048];
sprintf(command_line, "<path to executable to be started as child process> %Iu", (unsigned __int64)new_channel);
PROCESS_INFORMATION process_info;
memset(&process_info, 0, sizeof(PROCESS_INFORMATION));
STARTUPINFO startup;
memset(&startup, 0, sizeof(STARTUPINFO));
startup.cb = sizeof(STARTUPINFO);
CreateProcess(NULL, command_line, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &process_info); // note that bInheritHandles is set to TRUE (1)
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
CloseHandle(new_channel);
...
这是 CPE 的(简化)代码:
...
int pipeFd = atoi(argv[1]);
char *outBuf = ... // the message to be sent to the RAS as this is waiting for a (synchronous) response
int size = ... // length of this message
int cnt = send(pipeFd, outBuf, size, 0);
...
多年来,这一切都非常有效。现在我们想用一个用C#编写的程序来代替CPE,我们称之为CPE.NET。 WS 应该保持原样(用 C 编写)。
这是 CPE.NET 的(简化)代码:
class Program {
[DllImport("ws2_32.dll")]
extern static int send([In] IntPtr socketHandle, [In] IntPtr buffer, [In] int count, [In] SocketFlags socketFlags);
public static int Send(IntPtr socketHandle, byte[] buffer, int offset, int size, SocketFlags socketFlags) {
unsafe {
fixed (byte* pData = buffer) {
return send(socketHandle, new IntPtr(pData + offset), size, socketFlags);
}
}
}
static void Main(string[] args) {
int socketHandle;
if (!int.TryParse(args[1], out socketHandle))
return;
byte[] data = new byte[] { ... }; // the message to be sent to the RAS as this is waiting for a (synchronous) response
int retSendWithDotNet = Send(new IntPtr(socketHandle), data, 0, data.Length, 0);
...
现在的问题是 retSendWithDotNet 总是 -1。知道为什么会这样吗?
谢谢, 迈克尔
"You need to call WSAGetLastError to get more information. My guess is that sockets are not initialized (see WSAStartup)."
简单但有效。调用 WSAStartup() 就成功了。 非常感谢。