[Win32]防止套接字被继承

有一个网络应用程序,需要创建子进程,同时要将一个内核对象的句柄传递给子进程使用。句柄默认是不可继承的,为了达到这个目的,要在创建内核对象的时候指定其句柄是可继承的,然后在调用CreateProcess的时候将bInheritHandles参数设置为TRUE,像下面那样(以创建Mutex为例):

SECURITY_ATTRIBUTES sa = { 0 };
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;

HANDLE hMutex = CreateMutex(&sa, TRUE, L"Mutex");

STARTUPINFO si = { 0 };
//... 设置si的各个字段

PROCESS_INFORMATION pi;

CreateProcess(
	path,
	NULL,
	NULL,
	NULL,
	TRUE,
	0,
	NULL,
	NULL,
	&si,
	&pi
);

 

可是在使用句柄继承之后,这个网络应用程序出现了问题:当父进程结束而子进程没有结束的时候,原本与父进程连接的应用程序并没有收到连接中断的消息,它仍然在等待父进程(已不存在)发送的数据;直到把子进程也结束,连接才会中断。

 

对于这个问题的初步设想是:子进程把父进程的套接字也继承了,因此即使父进程结束了,套接字仍然是存在的,当子进程也结束的时候,套接字才会被真正地销毁。微软知识库中有一篇文章(http://support.microsoft.com/kb/150523/en-us?fr=1)可以证明这个假设,文中说Windows NT内核的操作系统创建的套接字默认是可继承的,不像其它内核对象那样需要显式进行设置,所以当CreateProcess的bInheritHandles参数为TRUE的时候,父进程中的套接字都被子进程继承了。

 

如果对这个说法有所怀疑,可以实际证明一下。下面是证明过程,如果不想看可以跳到最后看解决方法。

 

首先写一个简单的测试程序,创建一个套接字,然后创建子进程:

#include <iostream>
#include <string>
#include <WinSock2.h>

int wmain() {

	WSAData wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	STARTUPINFO si = { 0 };
	si.cb = sizeof(si);

	PROCESS_INFORMATION pi;

	CreateProcess(
		L"C:\\Windows\\notepad.exe",
		NULL,
		NULL,
		NULL,
		TRUE,
		0,
		NULL,
		NULL,
		&si,
		&pi
	);

	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);

	std::wstring line;
	while (std::getline(std::wcin, line)) { }

	WSACleanup();
}

 

运行该程序会启动一个记事本程序。接下来使用ProcessExplorer查看父进程中的句柄:

clip_image002

 

上图中的Win32Console.exe即是父进程。可以看到,在父进程中有一个句柄指向一个类型为File的内核对象,其名称是\Device\Afd,这是套接字在内核中表示,同时也可以看到该内核对象的引用计数是2,说明共有两个句柄指向该对象。

 

然后再看看子进程的情况:

clip_image004

 

在子进程中同样有一个指向名为\Device\Afd的内核对象的句柄,记事本程序没有网络功能,所以正常情况下它根本不会有套接字的。留意它的引用计数也是2,还有这个对象的地址与父进程中的是一样的。要是把CreateProcess的bInheritHandles参数改为FALSE,子进程就不会出现这个句柄了。

 

防止套接字被子进程继承的方法非常简单,只要在创建套接字之后立即使用SetHandleInformation设置它的可继承性即可。像这样:

SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SetHandleInformation((HANDLE)sock, HANDLE_FLAG_INHERIT, 0);
posted on 2012-03-20 19:47  Zplutor  阅读(2891)  评论(2编辑  收藏  举报