C++匿名管道详解及简单案例(基于VS2013)

首先放一张程序的运行图(程序下载地址),这里是父进程的一个命令行执行情况:


父进程的源文档中已经将子进程的执行程序放在了相对路径下,各位下载后直接运行父进程进行Debug即可得到效果,子进程程序供学习参考使用,这里先放上父进程的代码:

int main(int argc, char* argv[])
{

	SECURITY_ATTRIBUTES sa;  //定义一个安全结构体类型的变量Sa
	sa.bInheritHandle = TRUE;//让子进程可以继承父进程创建的匿名管道的读写句柄
	sa.lpSecurityDescriptor = NULL;//让系统为创建的匿名管道赋予默认的安全描述符
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);//得到结构体(SECURITY_ATTRIBUTES)的长度
	if (!CreatePipe(&hRead, &hWrite, &sa, 0))//判断创建匿名管道是否成功
	{
		cout << "创建匿名管道失败!\n";
		return 0;
	}
	else
		cout << "成功创建匿名管道!\n";
	//如果创建匿名管道成功,就启动子进程,并将匿名管道的读写句柄传递给子进程
	STARTUPINFO sui;//创建子进程的函数需要的一个结构体类型的值
	PROCESS_INFORMATION pi;
	ZeroMemory(&sui, sizeof(STARTUPINFO));//将其余的成员全部置零,避免造成不好的影响
	sui.cb = sizeof(STARTUPINFO);//cb用来存放结构体变量STARTUPINFO的长度
	sui.dwFlags = STARTF_USESTDHANDLES;//标志成员,表示当前STARTUPINFO结构体的标准输入,标准输出和标准错误句柄有用
	sui.hStdInput = hRead;
	sui.hStdOutput = hWrite;//将子进程的标准输入输出句柄分别设置为管道的读、写句柄
	sui.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	sui.wShowWindow = SW_SHOW; //隐藏命令行窗口
	sui.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	WriteMsg();
	if (!CreateProcess(NULL, "child.exe", NULL, NULL,
		TRUE, 0, NULL, NULL, &sui, &pi))//创建子进程(十个参数)
	{
		CloseHandle(hRead);
		CloseHandle(hWrite);//关闭句柄,将内核对象的使用计数减少1,这样当操作系统发现内核对象的使用计数为0时,将清除内核对象。
		hRead = NULL;
		hWrite = NULL;
		cout << "创建子进程失败!";
		return 0;
	}
	else
	{
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}


	Sleep(200);
	ReadMsg();
	return 0;
}

在说明创建函数之前我们需要先了解程序代码中涉及的几个结构体具体是干什么的(详细请查询库)

STARTUPINFO:用于指定新进程的主窗口特性的一个结构。
SECURITY_ATTRIBUTES:一个与安全相关的结构体。
PROCESS_INFORMATION:在创建进程时相关的数据结构之一,该结构返回有关新进程及其主线程的信息。

其余的代码的具体含义已经给予了非常详细的注释,这里只单说一下Create函数的各个参数的具体含义

CreateProcess("child.exe", NULL, NULL, NULL,TRUE, 0, NULL, NULL, &sui, &pi)
这里一共有十个参数
1、子进程应用程序的进程名
2、指定命令行参数,默认为NULL
3|4、进程和线程安全属性,默认为NULL,即使用系统默认安全属性
5、值为TRUE时,让父进程的每个可继承的打开句柄都能被子进程继承
6、创建标志,如不需要,置值为0
7、让新进程使用调用进程的环境、默认为NULL
8、让父进程和子进程拥有同样的驱动器和路径,默认为NULL
9、STARTUPINFO结构体实例化对象的地址(sui地址)
10、PROCESS_INFORMATION的地址(pi地址)

读数据代码:

void ReadMsg()
{
	char buf1[512];
	DWORD dwRead;
	if (!ReadFile(hRead, buf1, 512, &dwRead, NULL))
	{
		cout<<"读取数据失败!";
		return;
	}
	else
	{
		cout << "管道中读取数据为:"<<buf1;
		system("pause");
	}
}

写数据代码:

void WriteMsg()
{
	char buf[100];
	cout << "请输入你要发给子进程的消息:\n";
	cin >> buf;
	DWORD dwWrite;
	if (!WriteFile(hWrite, buf, strlen(buf), &dwWrite, NULL))
	{
		cout << "写入数据失败!";
		return;
	}
	else
		cout << "成功写入数据!\n";
}

相对于父进程,子进程相应就要简单很多了:

子进程读信息:

void ReadMsg()
{

	DWORD dwRead;
	if (!ReadFile(hRead, buf, 100, &dwRead, NULL))
	{
		cout<<"读取数据失败!";
		return;
	}
	sprintf(buf1, "子进程返回的数据为 %s!\n", buf);
	return;
}

子进程写信息:

void WriteMsg()
{
	DWORD dwWrite;
	if (!WriteFile(hWrite, buf1, strlen(buf1) + 1, &dwWrite, NULL))
	{
		cout << "写入数据失败!";
		return;
	}

}

子进程的主函数:

int main(int argc, char* argv[])
{
	hRead = GetStdHandle(STD_INPUT_HANDLE);//用于从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄(用来标识不同设备的数值)
	hWrite = GetStdHandle(STD_OUTPUT_HANDLE);
	ReadMsg();
	Sleep(200);
	WriteMsg();
	return 0;
}


全部评论

相关推荐

不愿透露姓名的神秘牛友
2025-12-17 16:48
今天九点半到公司,我跟往常一样先扫了眼电脑,屁活儿没有。寻思着没事干,就去蹲了个厕所,回来摸出手机刷了会儿。结果老板刚好路过,拍了我一下说上班别玩手机,我吓得赶紧揣兜里。也就过了四十分钟吧,我的直属领导把我叫到小隔间,上来就给我一句:“你玩手机这事儿把老板惹毛了,说白了,你可以重新找工作了,等下&nbsp;HR&nbsp;会来跟你谈。”&nbsp;我当时脑子直接宕机,一句话都没憋出来。后面&nbsp;HR&nbsp;找我谈话,直属领导也在旁边。HR&nbsp;说我这毛病不是一次两次了,属于屡教不改,不光上班玩手机,还用公司电脑看论文、弄学校的事儿。我当时人都傻了,上班摸鱼是不对,可我都是闲得发慌的时候才摸啊!而且玩手机这事儿,从来没人跟我说过后果这么严重,更没人告诉我在公司学个习也算犯错!连一次口头提醒都没有,哪儿来的屡教不改啊?更让我膈应的是,昨天部门刚开了会,说四个实习生里留一个转正,让大家好好表现。结果今天我就因为玩手机被开了。但搞笑的是,开会前直属领导就把我叫去小会议室,明明白白告诉我:“转正这事儿你就别想了,你的学历达不到我们部门要求,当初招你进来也没打算给你这个机会。”合着我没入贵厂的眼是吧?可我都已经被排除在转正名单外了,摸个鱼至于直接把我开了吗?真的太离谱了!
rush$0522:转正名单没进,大概率本来就没打算留你
摸鱼被leader发现了...
点赞 评论 收藏
分享
2025-12-27 22:01
北京邮电大学 Java
蛊界Go学长林剑行:北邮加粗放大
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务