匿名管道一般用于父子间进程通信
注意:匿名管道不允许异步操作,所以如在一个管道中写入数据,且缓冲区已满,那么除非另一个进程从管道中读出数据,从而腾出了缓冲区的空间,否则写入函数不会返回,还有如果管道中没有数据的话,读端那边会一直等待数据读取,会操作堵塞所以要用PeekNamedPipe这个api去获取管道中的数据,如果有数据的话就读取
因为匿名管道是单向的,只能一端读一端写,所以父子进程中能有读写两种操作必须得要创建两条管道
代码例子如下
父进程创建两条管道,把两条管道中一个读一个写分别给子进程
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;//设置管道的句柄可以继承,这样子进程才能继承到父进程的句柄从而获取到句柄
sa.lpSecurityDescriptor = NULL;
BOOL bRet = CreatePipe(
&m_hReadParent, //读出端句柄
&m_hWriteChild, //写入端句柄
&sa,
0); //使用默认的缓冲区大小
bRet = CreatePipe(
&m_hReadChild, //读出端句柄
&m_hWritePrent, //写入端句柄
&sa,
0); //使用默认的缓冲区大小
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = m_hReadChild;//用于设定进程的标准输入输出的句柄
si.hStdOutput = m_hWriteChild;//
ZeroMemory(&pi, sizeof(pi));
TCHAR szName[] = { _T("SubProcess") };
// Start the child process.
if (!CreateProcess(NULL,
szName,
NULL,
NULL,
TRUE, //继承父进程的句柄
0,
NULL,
NULL,
&si, //这时候需要把管道的句柄传进子进程了
&pi)
)
{
AfxMessageBox(_T("CreateProcess failed."));
}
父进程读写
CString csBuff;
GetDlgItemText(EDT_WRITE2, csBuff);
DWORD dwBytesToWrite = 0;
BOOL bRet = WriteFile(
m_hWritePrent,
csBuff.GetBuffer(),
csBuff.GetLength()*sizeof(TCHAR),
&dwBytesToWrite,
NULL);
if (!bRet)
{
AfxMessageBox(_T("写入管道失败!"));
}
TCHAR szBuff[MAXBYTE] = { 0 };
DWORD dwBytesToRead = 0;
DWORD dwBytesAvail = 0; //管道中可用字节数
PeekNamedPipe(m_hReadParent, NULL, NULL, NULL, &dwBytesAvail, NULL);
//如果管道中还有数据,则读取
if (dwBytesAvail > 0)
{
BOOL bRet = ReadFile(
m_hReadParent,
szBuff,
sizeof(szBuff),
&dwBytesToRead,
NULL);
if (!bRet)
{
AfxMessageBox(_T("读入管道失败!"));
}
SetDlgItemText(EDT_READ2, szBuff);
}
子进程获取句柄进行读写操作
//获取读出端句柄
STARTUPINFO si;
GetStartupInfo(&si);
TCHAR szBuff[MAXBYTE] = { 0 };
DWORD dwBytesToRead = 0;
DWORD dwBytesAvail = 0; //管道中可用字节数
PeekNamedPipe(si.hStdInput, NULL, NULL, NULL, &dwBytesAvail, NULL);
//如果管道中还有数据,则读取
if (dwBytesAvail > 0)
{
BOOL bRet = ReadFile(
si.hStdInput,
szBuff,
sizeof(szBuff),
&dwBytesToRead,
NULL);
if (!bRet)
{
AfxMessageBox(_T("写入管道失败!"));
}
SetDlgItemText(EDT_READ, szBuff);
}
写
//获取写出端句柄
/* STARTUPINFO si;
GetStartupInfo(&si);
si.hStdOutput;*/
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//第二种方法也可以获取管道读写句柄,因为我在父进程哪里把子进程的标准输入输出句柄设置为管道的读写句柄
CString csBuff;
GetDlgItemText(EDT_WRITE, csBuff);
DWORD dwBytesToWrite = 0;
BOOL bRet = WriteFile(
hOutput,
csBuff.GetBuffer(),
csBuff.GetLength()*sizeof(TCHAR),
&dwBytesToWrite,
NULL);
if (!bRet)
{
AfxMessageBox(_T("写入管道失败!"));
}