进程间通信---匿名管道

94 阅读1分钟

前言

在Windows系统中,匿名管道只能用于父子进程间的通信。

相关API函数

  1. CreatePipe: 创建匿名管道.
BOOL CreatePipe(
  [out]          PHANDLE               hReadPipe,
  [out]          PHANDLE               hWritePipe,
  [in, optional] LPSECURITY_ATTRIBUTES lpPipeAttributes,
  [in]           DWORD                 nSize
);

需要注意第三个参数的类型SECURIY_ATTRIBUTES结构体

typedef struct _SECURITY_ATTRIBUTES {
  DWORD  nLength;
  LPVOID lpSecurityDescriptor;
  BOOL   bInheritHandle;
} SECURITY_ATTRIBUTES

该结构体有一个bInheritHandle成员,它决定了子进程是否能够继承父进程的句柄,如果设置成FALSE,那么子进程无法父进程的匿名管道进行读写操作,一般设置成TRUE.

2. PeekNamedPipe: 判断管道中是否有数据, 只是判断,并不会读取数据, 如果读取数据可以用ReadFile等IO函数.

代码示例

以下代码展示了创建CMD子进程,并重定向CMD子进程的标准输入和标准输出句柄到匿名管道上面。在终端输入命令,并打印出CMD子进程的执行结果.

#include <windows.h>
#include <iostream>
#include <thread>

int main()
{

	HANDLE hReadPipe, hWritePipe;
	HANDLE hReadPipeShell, hWritePipeShell;       
	
	//设定管道的安全属性
	SECURITY_ATTRIBUTES securityAttributes = { 0 };
	securityAttributes.bInheritHandle = TRUE;
	securityAttributes.nLength = sizeof(securityAttributes);
	securityAttributes.lpSecurityDescriptor = NULL;

	CreatePipe(&hReadPipe, &hWritePipeShell, &securityAttributes, 0);
	CreatePipe(&hReadPipeShell, &hWritePipe, &securityAttributes, 0);

	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };

	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdError = hWritePipeShell;
	si.hStdOutput = hWritePipeShell;    //重定向 cmd 的标准输入和输出.
	si.hStdInput = hReadPipeShell;

	BOOL bRet = CreateProcess("C:\windows\system32\cmd.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
	
	std::jthread jth([&](){
		char buf[1024 * 10] = {0};
		DWORD BytesRead = 0;
		DWORD TotalBytesAvail = 0;
		while (PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &TotalBytesAvail, NULL))
		{
                    if (TotalBytesAvail > 0)
                    {
				if (ReadFile(hReadPipe, buf, sizeof(buf), NULL, NULL))
				{
					std::cout << buf;
					memset(buf, 0, sizeof(buf));
					continue;
				}	
			}
			else
			{
				Sleep(100);
				continue;
			}
		}
		
		});

	std::string cmd;
	while (1)
	{
		std::getline(std::cin, cmd);
		cmd += "\r\n";
		WriteFile(hWritePipe, cmd.c_str(), cmd.size(), NULL, NULL);
	}
	system("pause");
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
	CloseHandle(hWritePipe);
	CloseHandle(hReadPipe);
	return 0;
}