进程间通信--001:管道

引用: http://blog.163.com/e_rommel/blog/static/187383045201192645544328/

进程间通信的作用

        进程间需要数据传输、资源共享和事件通知。

进程间通信的方式

        管道通信(无名管道和命名管道)

        信号通信

         内存资源共享

         消息队列

         信号量

管道

       管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)在管道的头部读出数据。数据被一个进程读出后,将被从管道中删除,其它读进程将再不能读到这些数据。管道提供了简单的流控制机制,进程试图读空管道时,进程将阻塞。同样,管道已经满时,进程再试图向管道写入数据,进程将阻塞。

管道创建

       管道包括无名管道有名管道两种,前者用于父进程和子进程之间的通信,后者可用于运行同一系统中任意两个进程间的通信。

       无名管道由pipe()函数创建:

       int pipe(int pipefiledis[2])

       当一个管道创建时,它会建立两个文件描述符:

filedis[0]用于读管道,filedis[1]用于写管道。

管道关闭

        管道关闭只需将这两个文件描述符关闭即可,可以使用普通的close函数进行关闭。
管道的读写

 1.无名管道(用于父、子进程间的通信)

       管道用于不同进程间的通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。

注:必须在系统调用fork()前调用pipe(),否则子进程将不会继承文件描述符。

2.命名管道(用于任意两个进程间的通信)

2.1 创建

#include<sys/types.h>

#include<sys/stat.h>

int mkfifo(const char *pathname,mode_t mode)

pathname:FIFO文件名

mode:属性

一旦创建了FIFO就可以用open打开它,一般的访问函数(close、write、read等)都可以用于FIFO。

实质上来讲命名管道就是一个文件

2.2 操作

     当FIFO打开时,非阻塞标志(O_NONBLOCK)

     将对以后的读写产生如下的影响:

     1.没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。如试图读取空的FIFO,将导致进程阻塞;

     2.使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回,errno是ENXIO。


相应的,写一个无名管道代码看看:

功能:将ping localhost的结果重定向到当前的stdout

#include <stdio.h>
#include <windows.h>

int main(int argc, char **argv)
{
	HANDLE hReadPipe, hWritePipe;//创建读、写通道
	SECURITY_ATTRIBUTES saAttr;//用来设置读写通道的属性
	PROCESS_INFORMATION piProcInfo; //获取创建线程后返回的线程信息
	STARTUPINFO siStartInfo;
	
	char buf[4096];
	TCHAR cmd[256] = TEXT("ping localhost");//cmd /c ver
	DWORD dwRead;
	int ret;

	memset(&saAttr, 0, sizeof(saAttr));
	memset(&piProcInfo, 0, sizeof(piProcInfo));
	memset(&siStartInfo, 0, sizeof(siStartInfo));

	//设置管道的属性
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

	//创建管道
	if (0 == CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0))
	{
		printf("CreatePipe error!\n");
		return -1;
	}

	//设置将要创建的线程的属性,输入输出重定向等
	siStartInfo.cb = sizeof(STARTUPINFO);//管道大小
	siStartInfo.wShowWindow = SW_HIDE;//窗体显示项
	siStartInfo.hStdError = hWritePipe;
	siStartInfo.hStdOutput = hWritePipe;//输出重定向--写入
	siStartInfo.hStdInput = hReadPipe;//输入重定向--读取
	siStartInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;//只有设置该项,前边4行才有效

	Sleep(1);
	ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, NULL, NULL, NULL, &siStartInfo, &piProcInfo);
	//siStartInfo
	//指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
	//piProcInfo
	//指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。

	if (0 == ret) 
	{
		printf("Create process faile[%d].\n", GetLastError()); 
		return -1;
	}

	//没用,仅仅是一个写入的测试
	//这样可以向管道中写数据
	memcpy(buf,"-asasa---\n",10);
	buf[10]=0;
	dwRead = 10;
	ret = WriteFile(hWritePipe,buf,dwRead,&dwRead,NULL);

	//这样可以读取刚才写进去的数据
	ret = ReadFile(hReadPipe, buf, dwRead, &dwRead, NULL);
	buf[dwRead] = '\0';
	printf("%s", buf);


	//之所以现在就关闭写句柄,是因为下边的ReadFile:
	//The ReadFile function returns when one of the following conditions occur:
	//A write operation completes on the write end of the pipe. 
	//	The number of bytes requested is read. 
	//	An error occurs.
	//也就是说,如果这地方不关闭,下边的ReadFile会一直阻塞下去而无法结束,
	//但是我下边使用i假设20次还没读取到数据就关闭写入句柄,想达到同样效果,却依然不能停止阻塞,不解啊
	if (!CloseHandle(hWritePipe)) 
	{
		printf("Closing write handle fail.\n"); 
		return -1;
	}

	int i = 0;
	while(1)
	{
		memset(buf, 0, 1024);
		ret = PeekNamedPipe(hReadPipe, buf, 1024, &dwRead, 0, 0);
		if (dwRead > 0)
		{
			ret = ReadFile(hReadPipe, buf, dwRead, &dwRead, NULL);
			if (0 == ret)
			{
				if (!CloseHandle(hReadPipe)) 
				{
					printf("Closing Read handle fail.\n"); 
					return -1;
				}
				break;
			}
			buf[dwRead] = '\0';
			printf("%s", buf);

			i = 0;
		else
		{
			if (i++ > 20)
			{
				if (!CloseHandle(hWritePipe)) 
				{
					printf("Closing write handle fail.\n"); 
					return -1;
				}
				else
				{
					printf("Closing write handle success.\n");
				}
				i=0;
			}
			printf("++++++++++++ret = %d , dwRead = %d\n",ret,dwRead);

		}
		Sleep(200);
	}

	if (!CloseHandle(hReadPipe)) 
	{
		printf("Closing Read handle fail.\n"); 
		return -1;
	}

	return 0;
}

有关阻塞疑问,参考: http://blog.csdn.net/cwb0525/article/details/4423627

知识:

http://blog.chinaunix.net/uid-24148050-id-3022548.html

6个进程通信的例子:http://blog.csdn.net/jmy5945hh/article/details/7367532

深刻理解进程通信:http://www.ibm.com/developerworks/cn/linux/l-ipc/

接下来是有名字的管道的实现:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值