学习进程间通信 (一)匿名管道通信

由于项目所需,所以初学进程通信.使用的是两个控制台应用程序, 父进程发送信息到匿名管道,也有子进程发送.

匿名管道因为提供的功能很单一,所以它所需要的系统的开销也就比命名管道小很多,在本地机器上可以使用匿名管道来实现父进程和子进程之间的通信,这里有两点很重要,第一就是在本地机器上,这是因为匿名管道不支持跨网络之间的两个进程之间的通信,第二就是实现的是父进程和子进程之间的通信,而不是任意的两个进程。

匿名管道主要用于本地父进程和子进程之间的通信,在父进程中的话,首先是要创建一个匿名管道,在创建匿名管道成功后,可以获取到对这个匿名管道的读写句柄,然后父进程就可以向这个匿名管道中写入数据和读取数据了,但是如果要实现的是父子进程通信的话,那么还必须在父进程中创建一个子进程,同时,这个子进程必须能够继承和使用父进程的一些公开的句柄, 在子进程中必须要使用父进程创建的匿名管道的读写句柄,通过这个匿名管道才能实现父子进程的通信,所以必须继承父进程的公开句柄。同时在创建子进程的时候,必须将子进程的标准输入句柄设置为父进程中创建匿名管道时得到的读管道句柄,将子进程的标准输出句柄设置为父进程中创建匿名管道时得到的写管道句柄。然后在子进程就可以读写匿名管道了。


下面贴上自己的代码

先是服务器端service项目

#include "stdafx.h"
#include "windows.h"
#include <fstream>
#include "iostream"
#include <string.h>
#include <atlconv.h>//USES_CONVERSION



#define dataLength  100
int WriteToPipe(HANDLE &hPipeWrite,char *pSendData);
int ReadFromPipe(HANDLE &hPipeRead, char *SaveFilePath);
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	bool bPipeIsCreated = false;	//保证通道只建立一次


	SECURITY_ATTRIBUTES sa;	//该结构包含有一个对象的安全描述符以及返回的句柄是否可以被继承。该结构为由诸如CreateFile, CreatePipe, CreateProcess, RegCreateKeyEx, 或  RegSaveKeyEx 函数创建的对象提供安全设置。
	PROCESS_INFORMATION pi;	//在创建进程时相关的数据结构之一,该结构返回有关新进程及其主线程的信息.
	STARTUPINFO si;					//该结构用于指定新进程的主窗口特性.

	//对sa 进行赋值
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);

	//保存创建匿名管道后所得到的对匿名管道的读写句柄
	HANDLE hPipeRead;
	HANDLE hPipeWrite;

	if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0))
	{
		//return;//创建匿名通道失败
	}

	///对si的初始化/
	memset(&si, 0, sizeof(STARTUPINFO));

	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USESTDHANDLES;

	//子进程的标准输入句柄为父进程管道的读写数据句柄
	si.hStdInput = hPipeRead;
	si.hStdOutput = hPipeWrite;

	//子进程的标准错误处理句柄和父进程的标准错误处理句柄一致
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);

	/end


	创建子进程/
	if (!CreateProcess(_T("../Debug/client.exe"), 
		NULL, NULL, NULL, TRUE, 
		CREATE_NEW_CONSOLE, NULL, NULL, 
		&si, &pi))
	{
		CloseHandle(hPipeRead);
		CloseHandle(hPipeWrite);

		hPipeWrite = NULL;
		hPipeRead = NULL;
	
	}//end create
	else
	{
		bPipeIsCreated = TRUE;
		//这两个句柄不需要使用,所以释放资源
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
	}


///测试写通道
	char*pSendData = new char[dataLength];
	memset(pSendData, 0, dataLength);
	int i = 0;
	while (1)
	{
		sprintf(pSendData,"temp%d", i);
		
		WriteToPipe(hPipeWrite, pSendData);

		cout<<"一次写入循环结束"<<endl;
		Sleep(1000);
		i++;
	}
	

///测试读通道

	//ReadFromPipe(hPipeRead, "../Debug/ParentGetFromPipe.txt");


	return 0;
}

int WriteToPipe(HANDLE &hPipeWrite,char *pSendData)
{
	DWORD dwWrite;
	if (!WriteFile(hPipeWrite, pSendData, 100, &dwWrite, NULL))
	{
		//写入失败
		return -1;
	}
}


int ReadFromPipe(HANDLE &hPipeRead, char *SaveFilePath)
{
	DWORD            dwRead;
	char *            pReadBuf;
	pReadBuf = new char[dataLength];
	memset(pReadBuf, 0, dataLength);


	if (!ReadFile(hPipeRead, pReadBuf, dataLength, &dwRead, NULL))
	{
		return -1;
	}

	保存在文件中///
	ofstream fout;
	fout.open(SaveFilePath);
	fout<<pReadBuf;
	fout.close();
}


下面的是client客户端的代码:

#include "stdafx.h"
#include <stdio.h>
#include "iostream"
#include "windows.h"
#include <fstream>


#define dataLength 100
int ReadFromPipe(HANDLE &hPipeRead,char *pReadBuf, char *SaveFilePath);
int WriteToPipe(HANDLE &hPipeWrite);
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	//只需要获取一次匿名管道的读写句柄即可
	BOOL b_IsGettedParentHandle = false;

	HANDLE hPipeRead;
	HANDLE hPipeWrite;

	if (b_IsGettedParentHandle ==false)
	{
		hPipeRead = GetStdHandle(STD_INPUT_HANDLE);
		hPipeWrite = GetStdHandle(STD_OUTPUT_HANDLE);
		b_IsGettedParentHandle = TRUE;
	}

	//从管道中读取数据,数据保存在参数2中的文件中
	char * pReadBuf;
	pReadBuf = new char[dataLength];
	memset(pReadBuf, 0, dataLength);

	while(1)
	{

		ReadFromPipe(hPipeRead, pReadBuf, "../Debug/ChildGetFromPipe.txt");
	
		Sleep(50);
		
	}

	//	CloseHandle(hPipeRead);//注意什么时候用...
	///写数据
	//WriteToPipe(hPipeWrite);


	return 0;
}

int ReadFromPipe(HANDLE &hPipeRead,char *pReadBuf, char *SaveFilePath)//@@@@@@@@@@@@@@@
{
	DWORD dwRead;

	if (!ReadFile(hPipeRead, pReadBuf, dataLength, &dwRead, NULL))
	{
		return -1;
	}


	保存在文件中///
	ofstream fout;
	fout.open(SaveFilePath, ios::app);
	//fout.seekp(ios::end);
	fout<<pReadBuf<<endl;
	fout.close();
}

int WriteToPipe(HANDLE &hPipeWrite)
{
	char *  pSendData = "this is a message from the child!";
	DWORD dwWrite;
	if(!WriteFile(hPipeWrite, pSendData, 100, &dwWrite, NULL))
	{
		//写入失败
		return -1;
	}
}


运行时将service.exe和client.exe放在同一目录下,程序默认实现,父进程一秒发送一个"temp%d", i的数据到匿名通道,等待子进程读取出来保存到ChildGetFromPipe.txt文件中


刚刚接触, 若有错误,请指正,谢谢!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值