邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自http://www.cnblogs.com/kzloser/archive/2012/11/04/2753367.html#
邮槽
通信流程:
- 服务器

- 客户端

注意:
- 邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输
- 邮槽可以实现一对多的单向通信,我们可以利用这个特点编写一个网络会议通知系统,而且实现这一的系统所需要编写的代码非常少.如果读者是项目经理,就可以给你手下每一位员工的机器上安装上这个系统中的邮槽服务器端程序,在你自己的机器上安装油槽的客户端程序,这样,当你想通知员工开会,就可以通过自己安装的邮槽客户端程序.将开会这个消息发送出去,因为机器上都安装了邮槽服务器端的程序,所以他们都能同时收到你发出的会议通知.采用邮槽实现这一的程序非常简单的,如果采用Sockets来实现这一的通信,代码会比较复杂
- 邮槽是一种单向通信机制,创建邮槽的服务器进程只能读取数据,打开邮槽的客户机进程只能写入数据
- 为保证邮槽在各种Windows平台下都能够正常工作,我们传输消息的时候,应将消息的长度限制在424字节以下
CreateMailslot函数详解
函数原型:
HANDLE CreateMailslot(
LPCTSTR lpName, // mailslot name
DWORD nMaxMessageSize, // maximum message size
DWORD lReadTimeout, // read time-out interval
LPSECURITY_ATTRIBUTES lpSecurityAttributes // inheritance option
);参数说明:
- lpName
指向一个空终止字符串的指针,该字符串指定了油槽的名称,该名称的格式必须是:"\\.\mailslot\[path]name ",其中前两个反斜杠之后的字符表示服务器所在机器的名称,圆点表示是主机;接着是硬编码的字符串:"mailslot",这个字符串不能改变,但大小写无所谓;最后是油槽的名称([path]name)由程序员起名 - nMaxMessageSize
用来指定可以被写入到油槽的单一消息的最大尺寸,为了可以发送任意大小的消息,卡伊将该参数设置为0 - lReadTimeout
指定读写操作的超时间间隔,以ms为单位,读取操作在超时之前可以等待一个消息被写入到这个油槽之中.- 如果这个值设置为0,那么若没有消息可用,该函数立即返回;
- 如果这个值设置为MAILSOT_WAIT_FOREVER,则函数一直等待,直到有消息可用
- lpSecurityAttributes
指向一个SECURITY_ATTRIBUTES结构的指针,可以简单地给这个参数传递NULL值,让系统为所创建的油槽赋予默认的安全描述符
代码样例:
服务器端源码:
#include<windows.h>
#include<cstdlib>
#include<iostream>
using namespace std; void main()
{
HANDLE hMailslot;
char buf[];
DWORD dwRead; //创建邮槽
hMailslot=CreateMailslot("\\\\.\\mailslot\\Communication",,
MAILSLOT_WAIT_FOREVER,NULL);
if(INVALID_HANDLE_VALUE==hMailslot)
{
cout<<"创建邮槽失败!"<<endl;
system("pause");
return;
} //等待用户写入数据然后读取出数据
if(!ReadFile(hMailslot,buf,,&dwRead,NULL))
{
cout<<"读取数据失败!"<<endl;
CloseHandle(hMailslot);
system("pause");
return;
}
cout<<buf<<endl; //关闭邮槽
CloseHandle(hMailslot); system("pause");
}客户端源码:
#include<windows.h>
#include<cstdlib>
#include<iostream>
using namespace std; void main()
{
HANDLE hMailslot;
char buf[]="this is message"; //打开邮槽
hMailslot=CreateFile("\\\\.\\mailslot\\Communication",GENERIC_WRITE,
FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hMailslot)
{
cout<<"打开邮槽失败!"<<endl;
system("pause");
return;
} //向邮槽写数据
DWORD dwWrite;
if(!WriteFile(hMailslot,buf,strlen(buf)+,&dwWrite,NULL))
{
cout<<"写入数据失败!"<<endl;
CloseHandle(hMailslot);
system("pause");
return;
} //关闭邮槽
CloseHandle(hMailslot); system("pause");
}运行结果(先运行服务器端程序,然后在运行客户端程序):

匿名管道
说明:
匿名管道是一个未命名的,单向管道,通常用来在一个父进程和一个子进程之间传输数据,匿名管道只能实现在本机上的两个进程通信,而不能实现跨网络的通信
通信过程
- 父进程读写数据:

- 子进程读写数据:

相关函数
CreatePipe 管道创建
函数原型
BOOL CreatePipe(
PHANDLE hReadPipe, // pointer to read handle
PHANDLE hWritePipe, // pointer to write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // pointer to security attributes
DWORD nSize // pipe size
);参数说明:
- hReadPipe 作为返回类型使用,返回管道读取句柄
- hWritePipe 作为返回类型使用,返回管道写入句柄
- lpPipeAttributes 指向SECURITY_ATTRIBUTES结构体的指针,检测返回句柄是否能被子进程继承,如果此参数为NULL,则句柄不能被继承
- nSize 指定管道的缓冲区大小,改大小只是个建议值,系统将用这个值来计算一个适当的缓存区大小,如果此参数是0,系统会使用默认的缓冲区大小
返回值
若函数成功返回非零值
若函数失败返回0,详细消息可以调用GetLastError函数获得代码样例:
工程目录结构:
匿名管道
|-- child
| `-- debug
| `-- child.exe
` -- parent
`-- debug
`-- parent.exe父进程源码:
- 父进程读写数据:
#include<windows.h>
#include<iostream>
#include<cstdlib>
using namespace std; void main()
{
SECURITY_ATTRIBUTES sa;
STARTUPINFO sui;
PROCESS_INFORMATION pi;
HANDLE hRead,hWrite;
char rebuf[];
DWORD dwRead; //创建匿名管道
sa.bInheritHandle=TRUE;
sa.lpSecurityDescriptor=NULL;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
if(!CreatePipe(&hRead,&hWrite,&sa,))
{
cout<<"创建匿名管道失败!"<<endl;
system("pause");
return;
} //创建子进程并对相关子进程相关数据进行初始化 (用匿名管道的读取写入句柄赋予子进程的输入输出句柄)
ZeroMemory(&sui,sizeof(STARTUPINFO));
sui.cb=sizeof(STARTUPINFO);
sui.dwFlags=STARTF_USESTDHANDLES;
sui.hStdInput=hRead;
sui.hStdOutput=hWrite;
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE); if(!CreateProcess("..\\..\\child\\debug\\child.exe",NULL,NULL,NULL,true,CREATE_NEW_CONSOLE,NULL,NULL,&sui,&pi))
{
cout<<"创建子进程失败!"<<endl;
system("pause");
return;
}
else
{
//关闭子进程相关句柄(进行句柄,进程主线程句柄)
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); Sleep(); //读取数据
if(!ReadFile(hRead,rebuf,,&dwRead,NULL))
{
cout<<"读取数据失败!"<<endl;
system("pause");
return;
}
cout<<rebuf<<endl; }
system("pause");
}子进程源码:
#include<windows.h>
#include<iostream>
#include<cstdlib>
using namespace std; void main()
{
HANDLE hRead,hWrite; //获得匿名管道输入输出句柄
hRead=GetStdHandle(STD_INPUT_HANDLE);
hWrite=GetStdHandle(STD_OUTPUT_HANDLE);
char sebuf[]=" 子进程写入管道成功";
char rebuf[];
DWORD dwWrite; //写入数据
if(!WriteFile(hWrite,sebuf,strlen(sebuf)+,&dwWrite,NULL))
{
cout<<"写入数据失败!"<<endl;
system("pause");
return;
}
Sleep(); system("pause");
}
命名管道
作用
命名管道不仅可以实现在本机上两个进程间的通信,还可以跨网络实现两个进程间的通信
两种通信模式
- 字节模式: 在字节模式下,数据以一个连续的字节流的形式在客户机和服务器之间流动
- 消息模式: 在消息模式下,客户机和服务器则通过一系列不连续的数据单位,进行数据收发,每次在管道上发一条消息后,它必须作为一条完整的消息读入
通信流程
- 服务器

- 客户端

相关函数
代码样例:
服务器:
#include<windows.h>
#include<cstdlib>
#include<iostream>
using namespace std; void main()
{
HANDLE hPipe,hEvent;;
DWORD dwRead,dwWrite;
OVERLAPPED ovlap;
char sebuf[]="this is sever!";
char rebuf[]; /*创建命名连接*****************************************************/
hPipe=CreateNamedPipe("\\\\.\\pipe\\Communication",
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
,,,,,NULL);
if(INVALID_HANDLE_VALUE==hPipe)
{
cout<<"创建命名管道失败!"<<endl;
hPipe=NULL;
system("pause");
return;
} /*创建命名管道连接*************************************************/
hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
if(!hEvent)
{
cout<<"创建事件对象失败!"<<endl;
CloseHandle(hPipe);
hPipe=NULL;
system("pause");
return;
} ZeroMemory(&ovlap,sizeof(OVERLAPPED));
ovlap.hEvent=hEvent; //创建管道连接
if(!ConnectNamedPipe(hPipe,&ovlap))
{
if(ERROR_IO_PENDING!=GetLastError())
{
cout<<"等待客户端连接失败!"<<endl;
CloseHandle(hPipe);
CloseHandle(hEvent);
hPipe=NULL;
system("pause");
return;
}
}
//等待客户端连接
if(WAIT_FAILED==WaitForSingleObject(hEvent,INFINITE))
{
cout<<"等待对象失败!"<<endl;
CloseHandle(hPipe);
CloseHandle(hEvent);
hPipe=NULL;
system("pause");
return;
}
CloseHandle(hEvent); /*读写管道数据*****************************************************/
//写入数据
if(!ReadFile(hPipe,rebuf,,&dwRead,NULL))
{
cout<<"读取数据失败!"<<endl;
system("pause");
return;
}
cout<<rebuf<<endl; //写入数据
if(!WriteFile(hPipe,sebuf,strlen(sebuf)+,&dwWrite,NULL))
{
cout<<"写入数据失败!"<<endl;
system("pause");
return;
} system("pause");
}- 客户端:
#include<windows.h>
#include<cstdlib>
#include<iostream>
using namespace std; void main()
{
HANDLE hPipe;
DWORD dwRead,dwWrite;
char sebuf[]="this is client!";
char rebuf[]; /*连接管道连接*****************************************************/
if(!WaitNamedPipe("\\\\.\\pipe\\Communication",NMPWAIT_WAIT_FOREVER))
{
cout<<"当前没有可利用的命名管道实例!"<<endl;
system("pause");
return;
} /*打开管道连接*****************************************************/
hPipe=CreateFile("\\\\.\\pipe\\Communication",GENERIC_READ | GENERIC_WRITE,
,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hPipe)
{
cout<<"打开命名管道失败!"<<endl;
hPipe=NULL;
system("pause");
return;
} /*读写管道数据*****************************************************/
//写入数据
if(!WriteFile(hPipe,sebuf,strlen(sebuf)+,&dwWrite,NULL))
{
cout<<"写入数据失败!"<<endl;
system("pause");
return;
} //读取数据
if(!ReadFile(hPipe,rebuf,,&dwRead,NULL))
{
cout<<"读取数据失败!"<<endl;
system("pause");
return;
}
cout<<rebuf<<endl; system("pause");
}
剪贴板
通信流程
- 接收数据

- 发送数据

相关函数
- 接收数据
程序样例:
#include<windows.h>
#include<cstdlib>
#include<iostream>
#include<string>
using namespace std; void main()
{
HANDLE hClip;
char *pBuf;
string str="this is message"; /*向剪贴板写入数据************************************************************************/
//打开剪贴板
if(OpenClipboard(NULL))
{
//清空剪贴板
EmptyClipboard(); //想剪贴板写入数据
hClip=GlobalAlloc(GMEM_MOVEABLE,str.size()+);
pBuf=(char*)GlobalLock(hClip);
strcpy(pBuf,str.c_str());
GlobalUnlock(hClip);
SetClipboardData(CF_TEXT,hClip); //释放剪贴板
CloseClipboard();
} /*从剪贴板读取数据************************************************************************/
//打开剪贴板
if(OpenClipboard(NULL))
{
//检查剪贴板中的数据格式
if(IsClipboardFormatAvailable(CF_TEXT))
{
//接收数据
hClip=GetClipboardData(CF_TEXT);
pBuf=(char*)GlobalLock(hClip);
GlobalUnlock(hClip);
cout<<pBuf<<endl; //释放剪贴板
CloseClipboard();
}
}
system("pause");
}运行结果:

邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自http://www.cnblogs.com/kzloser/archive/2012/11/04/2753367.html#的更多相关文章
- Linux匿名管道与命名管道
http://blog.chinaunix.net/uid-26000296-id-3408970.html /* * \File * main.c * \Descript * father-proc ...
- [C++] socket -8 [命名管道]
::命名管道不但能实现同一台机器上两个进程通信,还能在网络中不同机器上的两个进程之间的通信机制.与邮槽不同,命名管道是采用基于连接并且可靠的传输方式,所以命名管道传输数据只能一对一进行传输. /* 命 ...
- Linux中的pipe(管道)与named pipe(FIFO 命名管道)
catalogue . pipe匿名管道 . named pipe(FIFO)有名管道 1. pipe匿名管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常 ...
- 操作系统-进程通信(信号量、匿名管道、命名管道、Socket)
进程通信(信号量.匿名管道.命名管道.Socket) 具体的概念就没必要说了,参考以下链接. 信号量 匿名管道 命名管道 Socket Source Code: 1. 信号量(生产者消费者问题) #i ...
- shell 匿名管道和命名管道
管道的特点:如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作:同理,写入管道的操作如果没有读取管道的操作,这一动作也会滞留. 1,匿名管道 匿名管道使用 ...
- Linux进程间通信(四):命名管道 mkfifo()、open()、read()、close()
在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关 ...
- IPC——命名管道
Linux进程间通信——使用命名管道 转载:http://blog.csdn.net/ljianhui/article/details/10202699 在前一篇文章——Linux进程间通信——使用匿 ...
- Linux进程间通信——使用命名管道
在前一篇文章——Linux进程间通信——使用匿名管道中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程 ...
- linux内核情景分析之命名管道
管道是一种"无名","无形文件,只可以近亲进程使用,不可以再任意两个进程通信使用,所以只能实现"有名","有形"的文件来实现就可以 ...
随机推荐
- Hibernate环境搭建+struts整合
说明:本文档,是和struts2+hibernate的整合示例. lib下还有struts2的jar包,本示例没有显示.struts2的搭建参考struts2的环境搭建 一下载hibernate的ja ...
- vue中去掉url地址栏中的#符号
要去掉vue中访问地址中的#符号可以在路由器中设置路由模式为history: export default new Router({ mode:'history', routes: [ { path: ...
- cratedb joins 原理(官方文档)
JOINs are essential operations in relational databases. They create a link between rows based on c ...
- IAR 9+ 编译 TI CC2541 出现 Segment ISTACK (size: 0xc0 align: 0) is too long for segment definition.
IAR 9+ 编译 TI CC2541 出现 Segment ISTACK (size: 0xc0 align: 0) is too long for segment definition. Segm ...
- php fwrite写入文件bom头导致的乱码问题解决
最近导出文件遇到fwrite导出乱码,而且中英文都乱码,很费解.折腾了一番之后终于找到问题所在了,mark下. UTF-8 BOM 又叫 UTF-8 签名,其实 UTF-8 的 BOM 对 UFT-8 ...
- emacs之配置php
php-setting.el (require 'php-mode) 以后丰富
- VS2015 Git 源代码管理工具使用记录
1. 首先到源代码托管平台申请个账户:https://git.oschina.net/ 2.创建流程图: 2.1 开始创建项目: 2.2 3. 4.
- mac下搭建appium记录
要安装的东西: jdk(要配置环境) , sdk(要配置环境) ,node(要配置环境), python(要配置环境) ,appium(要配置环境),appium-python-client ,xco ...
- Java-Runoob-高级教程-实例-环境设置实例:4.Java 实例 – 如何查看当前 Java 运行的版本?
ylbtech-Java-Runoob-高级教程-实例-环境设置实例:4.Java 实例 – 如何查看当前 Java 运行的版本? 1.返回顶部 1. Java 实例 - 如何查看当前 Java 运行 ...
- Androdi Gradle build project info 很慢
Androdi Gradle build project info 很慢 http://blog.csdn.net/stupid56862/article/details/78345584 原创 ...