邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自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内核情景分析之命名管道
管道是一种"无名","无形文件,只可以近亲进程使用,不可以再任意两个进程通信使用,所以只能实现"有名","有形"的文件来实现就可以 ...
随机推荐
- imshow(K)和imshow(K,[]) 的区别
参考文献 imshow(K)直接显示K:imshow(K,[])显示K,并将K的最大值和最小值分别作为纯白(255)和纯黑(0),中间的K值映射为0到255之间的标准灰度值.
- IOS中UITableViewCell使用详解
IOS中UITableViewCell使用详解 - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(N ...
- 20165212实验三——敏捷开发与XP实践
20165212实验三 敏捷开发与XP实践 实验内容 XP基础 XP核心实践 相关工具 实验知识点总结 (一)敏捷开发与XP 软件工程:把系统的.有序的.可量化的方法应用到软件的开发.运营和维护上的过 ...
- flow 编写flow-typed 定义(官方文档)
此为官方文档,因为墙的问题,记录下来: Before spending the time to write your own libdef, we recommend that you look to ...
- Oracle数据库导入导出(备份还原)
一.数据库的导出 1 将数据库TEST完全导出,用户名system 密码manager 导出到D:\daochu.dmp中(全库导出) exp system/manager@TEST file=d:\ ...
- socket编程---UDP
头文件 #include <sys/types.h> #include <sys/socket.h> 函数原型 int sendto (int s, const void *b ...
- java自动装箱和自动拆箱
启蒙:https://droidyue.com/blog/2015/04/07/autoboxing-and-autounboxing-in-java/ 1,比较:=比就和string一样比较地址,有 ...
- Lucene/Solr搜索引擎开发笔记 - 写作方向调整
今天突然想到一个问题,觉得直接从Solr开始写,如果没有Lucene知识背景的话,看后续的章节还是比较吃力的,所以从下一篇博文开始,我可能会从Lucene开始写作,只要有Java的基础,搞定Lucen ...
- oracle数据库启动时出现ORA-01157和ORA-01110问题
sql>startup mount; sql>alter database open; RA-01157: 无法标识/锁定数据文件 10 - 请参阅 DBWR 跟踪文件ORA-01110: ...
- staltStack安装配置
http://www.cnblogs.com/kevingrace/p/5570290.html