首页
社区
课程
招聘
Windows系统编程之进程间通信
发表于: 2006-5-25 14:18 39757

Windows系统编程之进程间通信

2006-5-25 14:18
39757

Windows系统编程之进程间通信
作者:北极星2003
来源:看雪论坛(www.pediy.com)
Windows 的IPC(进程间通信)机制主要是异步管道和命名管道。(至于其他的IPC方式,例如内存映射、邮槽等这里就不介绍了)
管道(pipe)是用于进程间通信的共享内存区域。创建管道的进程称为管道服务器,而连接到这个管道的进程称为管道客户端。一个进程向管道写入信息,而另外一个进程从管道读取信息。
异步管道是基于字符和半双工的(即单向),一般用于程序输入输出的重定向;命名管道则强大地多,它们是面向消息和全双工的,同时还允许网络通信,用于创建客户端/服务器系统。
一、异步管道(实现比较简单,直接通过实例来讲解)
实验目标:当前有sample.cpp, sample.exe, sample.in这三个文件,sample.exe为sample.cpp的执行程序,sample.cpp只是一个简单的程序示例(简单求和),如下:

#include <iostream.h>
int main()
{
	int a, b ;
	while ( cin >> a >> b && ( a || b ) )
		cout << a + b << endl ;
	return 0;
}
#include <windows.h> 
#include <iostream.h>

const int BUFSIZE = 4096 ; 
HANDLE	hChildStdinRd, hChildStdinWr, hChildStdinWrDup, 
	     hChildStdoutRd,hChildStdoutWr,hChildStdoutRdDup, 
		hSaveStdin,		hSaveStdout; 

BOOL CreateChildProcess(LPTSTR); 
VOID WriteToPipe(LPTSTR); 
VOID ReadFromPipe(LPTSTR); 
VOID ErrorExit(LPTSTR); 
VOID ErrMsg(LPTSTR, BOOL); 
void main( int argc, char *argv[] ) 
{	
	// 处理输入参数
	if ( argc != 4 )
		return ;

	// 分别用来保存命令行,输入文件名(CPP/C),输出文件名(保存编译信息)
	LPTSTR lpProgram = new char[ strlen(argv[1]) ] ;
	strcpy ( lpProgram, argv[1] ) ;
	LPTSTR lpInputFile = new char[ strlen(argv[2]) ];
	strcpy ( lpInputFile, argv[2] ) ;
	LPTSTR lpOutputFile = new char[ strlen(argv[3]) ] ;
	strcpy ( lpOutputFile, argv[3] ) ;		
	
	SECURITY_ATTRIBUTES saAttr; 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 
	 
	/************************************************
	 *		redirecting child process's STDOUT	*
	 ************************************************/
	hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
	
	if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 
		ErrorExit("Stdout pipe creation failed\n"); 
		
	if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) 
		ErrorExit("Redirecting STDOUT failed"); 
	
	BOOL fSuccess = DuplicateHandle(
		GetCurrentProcess(), 
		hChildStdoutRd,
        GetCurrentProcess(), 
		&hChildStdoutRdDup ,
		0,
        FALSE,
        DUPLICATE_SAME_ACCESS);
    if( !fSuccess )
        ErrorExit("DuplicateHandle failed");
    CloseHandle(hChildStdoutRd);
	
	/************************************************
	 *		redirecting child process's STDIN		*
	 ************************************************/
	hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 

	if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) 
		ErrorExit("Stdin pipe creation failed\n"); 
	
	if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) 
		ErrorExit("Redirecting Stdin failed"); 
	
	fSuccess = DuplicateHandle(
		GetCurrentProcess(), 
		hChildStdinWr, 
		GetCurrentProcess(),
		&hChildStdinWrDup, 
		0, 
		FALSE,                 
		DUPLICATE_SAME_ACCESS); 
	if (! fSuccess) 
		ErrorExit("DuplicateHandle failed"); 
	CloseHandle(hChildStdinWr); 	

	/************************************************
	 *			创建子进程(即启动SAMPLE.EXE)		*
	 ************************************************/
	fSuccess = CreateChildProcess( lpProgram );
	if ( !fSuccess ) 
		ErrorExit("Create process failed"); 
	
	// 父进程输入输出流的还原设置
	if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) 
		ErrorExit("Re-redirecting Stdin failed\n"); 
	if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) 
		ErrorExit("Re-redirecting Stdout failed\n"); 

	WriteToPipe( lpInputFile ) ;
	ReadFromPipe( lpOutputFile ); 
          delete lpProgram ;
          delete lpInputFile ;
          delete lpOutputFile ;
} 

BOOL CreateChildProcess( LPTSTR lpProgram ) 
{ 
	PROCESS_INFORMATION piProcInfo; 
	STARTUPINFO siStartInfo;
	BOOL bFuncRetn = FALSE; 
	
	ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
	ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
	siStartInfo.cb = sizeof(STARTUPINFO); 
	
	bFuncRetn = CreateProcess ( NULL, lpProgram, NULL, NULL, TRUE, \
								0, NULL, NULL, &siStartInfo, &piProcInfo);
	if (bFuncRetn == 0) 
	{
		ErrorExit("CreateProcess failed\n");
		return 0;
	} 
	else 
	{
		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);
		return bFuncRetn;
	}
}

VOID WriteToPipe( LPTSTR lpInputFile ) 
{ 
	HANDLE hInputFile = CreateFile(lpInputFile, GENERIC_READ, 0, NULL, 
		OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); 
	if (hInputFile == INVALID_HANDLE_VALUE) 
		return ;

	BOOL fSuccess ;
	DWORD dwRead, dwWritten; 
	CHAR chBuf[BUFSIZE] = {0} ; 
	
	for (;;) 
	{ 
		fSuccess = ReadFile( hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ;
		if ( !fSuccess || dwRead == 0)
			break; 

		fSuccess = WriteFile( hChildStdinWrDup, chBuf, dwRead, &dwWritten, NULL) ;
		if ( !fSuccess ) 
			break; 
	} 
		
	if (! CloseHandle(hChildStdinWrDup)) 
		ErrorExit("Close pipe failed\n"); 

	CloseHandle ( hInputFile ) ;
} 

VOID ReadFromPipe( LPTSTR lpOutputFile ) 
{ 
	HANDLE hOutputFile = CreateFile( lpOutputFile, GENERIC_READ|GENERIC_WRITE, 
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
	if (hOutputFile == INVALID_HANDLE_VALUE) 
		return ;

	BOOL fSuccess ;
	DWORD dwRead, dwWritten; 
	CHAR chBuf[BUFSIZE] = { 0 }; 
	
	if (!CloseHandle(hChildStdoutWr)) 
		ErrorExit("Closing handle failed"); 
	
	for (;;) 
	{ 
		fSuccess = ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, NULL) ;
		if( !fSuccess || dwRead == 0) 
		{
			break; 
		}
		fSuccess = WriteFile( hOutputFile, chBuf, dwRead, &dwWritten, NULL) ;
		if ( !fSuccess ) 
			break; 
	} 

	CloseHandle ( hOutputFile ) ;
} 
VOID ErrorExit (LPTSTR lpszMessage) 
{ 
	MessageBox( 0, lpszMessage, 0, 0 ); 
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (44)
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
果然是好东东.....谢谢楼主......学习了.........
2006-5-25 14:25
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
study...有没有VB版的
2006-5-25 14:55
0
雪    币: 603
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
4
勤奋啊~
2006-5-25 15:11
0
雪    币: 254
活跃值: (126)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
5
三天不学习,敢不上LSQ
三天不用功,敢不上MZD
2006-5-25 15:21
0
雪    币: 196
活跃值: (135)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
6
HOHO....学完之后提点建议

  LPTSTR lpProgram = new char( sizeof(argv[1]) ) ;
  strcpy ( lpProgram, argv[1] ) ;
  LPTSTR lpInputFile = new char( sizeof(argv[2]) ) ;
  strcpy ( lpInputFile, argv[2] ) ;
  LPTSTR lpOutputFile = new char( sizeof(argv[3]) ) ;
  strcpy ( lpOutputFile, argv[3] ) ;   

这段内存没有被释放,另外这个写法好像也有点问题(虽然可以正常运行),不知这样改一下如何:
  LPTSTR lpProgram = new char[ sizeof(argv[1]) ] ;
  strcpy ( lpProgram, argv[1] ) ;
  LPTSTR lpInputFile = new char[ sizeof(argv[2]) ] ;
  strcpy ( lpInputFile, argv[2] ) ;
  LPTSTR lpOutputFile = new char[ sizeof(argv[3]) ] ;
  strcpy ( lpOutputFile, argv[3] ) ;   

吹毛求疵之举,兄弟不要见怪
2006-5-25 15:26
0
雪    币: 234
活跃值: (370)
能力值: ( LV9,RANK:530 )
在线值:
发帖
回帖
粉丝
7
学习!
2006-5-25 16:23
0
雪    币: 217
活跃值: (99)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
最初由 thinkSJ 发布
LPTSTR lpProgram = new char( sizeof(argv[1]) ) ;
strcpy ( lpProgram, argv[1] ) ;
LPTSTR lpInputFile = new char( sizeof(argv[2]) ) ;
strcpy ( lpInputFile, argv[2] ) ;
LPTSTR lpOutputFile = new char( sizeof(argv[3]) ) ;
strcpy ( lpOutputFile, argv[3] ) ;
这段内存没有被释放,另外这个写法好像也有点问题(虽然可以正常运行),不知这样改一下如何:
LPTSTR lpProgram = new char[ sizeof(argv[1]) ] ;
strcpy ( lpProgram, argv[1] ) ;
LPTSTR lpInputFile = new char[ sizeof(argv[2]) ] ;
strcpy ( lpInputFile, argv[2] ) ;
LPTSTR lpOutputFile = new char[ sizeof(argv[3]) ] ;
strcpy ( lpOutputFile, argv[3] ) ;

我认为应该改成:
  LPTSTR lpProgram = new char[ strlen(argv[1])+1 ] ;
  strcpy ( lpProgram, argv[1] ) ;
  LPTSTR lpInputFile = new char[ strlen(argv[2])+1 ] ;
  strcpy ( lpInputFile, argv[2] ) ;
  LPTSTR lpOutputFile = new char[ strlen(argv[3])+1 ] ;
  strcpy ( lpOutputFile, argv[3] ) ;
因为sizeof(argv[1])=4.
2006-5-25 17:58
0
雪    币: 235
活跃值: (41)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
9
学习,学习 !
2006-5-25 18:32
0
雪    币: 560
活跃值: (359)
能力值: ( LV13,RANK:1370 )
在线值:
发帖
回帖
粉丝
10
值得学习!
2006-5-25 19:38
0
雪    币: 196
活跃值: (135)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
11
学习!!
2006-5-25 19:54
0
雪    币: 159
活跃值: (339)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
12
正需要这方面的东西呢
2006-5-25 20:24
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
13
6楼的正确!另外8楼的也对

多谢给意见!
写的仓促,我会尽快修改下
2006-5-25 20:59
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14

好东西,收下了
2006-5-27 01:42
0
雪    币: 260
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
难得的好资料
2006-6-2 09:29
0
雪    币: 421
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
只是来学习ing!
2006-6-3 10:08
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
学习ing
2006-6-3 22:06
0
雪    币: 214
活跃值: (70)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
18
谢谢楼主的好东东
2006-6-4 15:28
0
雪    币: 212
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
强人,学习到了新技术
2006-6-13 16:24
0
雪    币: 122
活跃值: (45)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
5)。操作B:子进程从输入管道中读取数据,作为该进程的加工原料。通常,程序的输入数据由标准的输入设备输入,一般为屏幕,这里实现输入重定向,即把输入管道作为输入设备。

楼主说的STDIN一般应该是键盘鼠标之类的吧!屏幕应该只是STDOUT,不知道楼主是怎么理解的?
2006-6-13 21:05
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
21
Originally posted by figofuture
5)。操作B:子进程从输入管道中读取数据,作为该进程的加工原料。通常,程序的输入数据由标准的输入设备输入,一般为屏幕,这里实现输入重定向,即把输入管道作为输入设备。

楼主说的STDIN一般应该是键盘鼠标之类的吧!屏幕应该只是STDOUT,不知道楼主是怎么理解的?


多写指出
2006-6-13 21:37
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
写得真是不错!管道流程图描述听清晰的!学习学习!
2006-6-15 17:08
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
学习之中...............
2006-6-21 05:44
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
辛苦楼主了.
2006-6-25 22:39
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
首先对楼主贡献的资料深感谢意.刚好要用到这方面的东西,真是雪中送碳.
但这里还有一些问题要请教楼主
1)在查找命名管道资料地过程中也看了<WINDOWS网络编程技术>这本书,其中讲到
  实现对管道实例的处理有两种方法,一是通过多线程,每个线程处理一个实例,
   二是通过IO重叠机制.但楼主的例子中两者都用到了.所以我想了解一下IO重叠机制的原理是什么?在什么情况下用得着?

2)还麻烦楼主帮我解决一下我遇到的问题,
我的应用程序中有两个服务进程,要达到的目的是这样:

1)第一个服务器进程通过命名管道向n个客户端进程传送数据(单向的),服务器写客户机收。

2)第二个服务进程跟第一个刚好相反,n个客户端进程将处理好的数据传给第二个服务端进程,客户端写服务端收。

因为服务器端进程还涉及到与外界交互,用多线程的话又涉及数据共享数据问

题,要考虑并发,因此想用一个线程处理多个管道实例.另外,我这个应用中,

服务端进程发送的数据是随机的,各个客户端进程处理的效率也不一样(但可以

保证不会因为客户端进程来不及处理和接收数据造成数据丢失),因此还需要注

意哪些问题来避免传输过程中数据丢失?

在这里先向楼主和各位前辈谢过了!

QQ:68844959
MSN:HE_YIBIN@SINA.COM
2006-6-26 16:34
0
游客
登录 | 注册 方可回帖
返回
//