在Windows中,大多数种类的手柄可以通过子进程继承。 人们期望,TCP套接字还可以继承。 但是,安装某些分层服务提供者时,这并不会达到预期效果(A / V产品,如赛门铁克PCTOOLS用于使我们为客户提供应用程序的问题)。
微软已经architectured的WinSock的方式,我们应该期望能够正确地继承SOCKET的?
在Windows中,大多数种类的手柄可以通过子进程继承。 人们期望,TCP套接字还可以继承。 但是,安装某些分层服务提供者时,这并不会达到预期效果(A / V产品,如赛门铁克PCTOOLS用于使我们为客户提供应用程序的问题)。
微软已经architectured的WinSock的方式,我们应该期望能够正确地继承SOCKET的?
不,插座应不会被标记可继承。 当某些分层服务提供商(LSP)安装,继承手柄根本无法在孩子使用。
作为一个额外的刺激,请参阅相关的问题“可以TCP套接字被标记为非遗传的?” 。 简单地说,你可以不依赖于能够继承插座,但也不能被继承停止插座!
可悲的是,这违背了一些微软自己的实例和文档(如KB150523 )。 简而言之,分层服务提供者是一个办法微软提供了第三方软件应用程序,并在他们的WinSock的DLL微软的TCP / UDP栈之间插入本身。 对于因某些LSP函数,它们使得人们很难进程之间传输插座,因为LSP关联与它要求在场每个插座一些本地信息。
由于LSP只是钩住的WinSock功能; 例如,调用DuplicateHandle
安装一些LSP时的插座上是行不通的,因为它是一个句柄级功能和LSP是永远不会有机会复制所需的信息。 (这是简单,但在明确提出DuplicateHandle
文档 )。
同样,尝试设置套接字句柄是可继承将复制手柄没有通知LSP,具有相同的结果:重复的手柄可以不通过Winsock的子进程的认可。 典型错误是WSAENOTSOCK(10038, “上nonsocket插槽操作”),或甚至ERROR_INVALID_HANDLE(6中, “句柄无效”)。
假设你想要写一个Windows程序,启动一个孩子重定向stdin和stdout,把它的一些数据,因此它知道来处理数据,然后等待孩子回到孩子的标准输入信号EOF。
让我们进一步假设该发射的一些富有想象力的形式进行,这意味着你的孩子也许并不是在所有(例如gksu / RunAs的孩子推出的包装,必须立即退出,让你只用插座连接客户端)。 你也不要因此有孩子的PID伺候。
该行为将类似于此:
int main(int argc, char* argv[]) {
int handles[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, handles);
if (fork()) {
// child
close(handles[0]);
dup2(handles[1], 0);
dup2(handles[1], 1);
execl("clever-app", "clever-app", (char*)0);
}
// parent
close(handles[1]);
char* data[100];
write(handles[0], data, sizeof(data)); // should at least check for EINTR...
// tell the app we called there's nothing more to read from stdin:
shutdown(handles[0], SHUT_WR);
// wait until child has exited (discarding all output)
while (read(handles[0], data, sizeof(data)) >= 0) ;
// now continue with the rest of the program...
}
在机器没有分层服务提供者,从而形成一对连接TCP套接字,并且在子作为标准输入/输出继承一个,是否正确运行。 人们很容易使用的解决方法socketpair
在Windows行为(记得送现时!)。
可悲的是,但SOCKET根本无法可靠地继承。 写在Windows上几乎等同功能的东西,你需要使用命名管道。 拨打电话之前CreateProcess
,打造一双,而不是使用连接的手柄CreateNamedPipe
/ ConnectNamedPipe
和朋友( GetOverlappedResult
用于重叠父句柄)。 (对孩子的手柄,用作标准输入,必须不能重复!)为孩子的手柄可以设置可继承,孩子将在它正常通信。
当您完成管道数据到客户端,调用FlushFileBuffers
和CloseHandle
父手柄上。
What about waiting for the child to exit before continuing, using only the handle? There isn't a way to do that directly with just the pipe to it; Windows pipes can't be half-closed. Ways to do this:
OpenProcess
converts a pid to a handle, so if you're careful to check the pid a second time after the OpenProcess
call, you can get rid of the race condition that would make this not possible on Unix.) Using a process handle like this is nonetheless a right pain because you'll probably find you need a second named pipe connection to send it over, depending on how you write your runas wrapper.A gotcha: How does the child receive notification that the parent has finished writing to its stdin? If the parent tries to call DisconnectClient
, the child doesn't get a normal EOF. Depending on what you're trying to execute, this may be a problem. When the parent shuts down a SOCKET, you do get feof
, but if a handle is connected to a child's stdin, the child will get a read error without getting EOF signalled to it. This may cause the child not to work in exactly the same way as if it were hooked up to stdin normally. Calling CloseHandle in the parent instead gives the right behaviour in the child.