邮槽

通信流程:

  • 服务器

  • 客户端

  • 注意:

    • 邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输
    • 邮槽可以实现一对多的单向通信,我们可以利用这个特点编写一个网络会议通知系统,而且实现这一的系统所需要编写的代码非常少.如果读者是项目经理,就可以给你手下每一位员工的机器上安装上这个系统中的邮槽服务器端程序,在你自己的机器上安装油槽的客户端程序,这样,当你想通知员工开会,就可以通过自己安装的邮槽客户端程序.将开会这个消息发送出去,因为机器上都安装了邮槽服务器端的程序,所以他们都能同时收到你发出的会议通知.采用邮槽实现这一的程序非常简单的,如果采用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#的更多相关文章

  1. Linux匿名管道与命名管道

    http://blog.chinaunix.net/uid-26000296-id-3408970.html /* * \File * main.c * \Descript * father-proc ...

  2. [C++] socket -8 [命名管道]

    ::命名管道不但能实现同一台机器上两个进程通信,还能在网络中不同机器上的两个进程之间的通信机制.与邮槽不同,命名管道是采用基于连接并且可靠的传输方式,所以命名管道传输数据只能一对一进行传输. /* 命 ...

  3. Linux中的pipe(管道)与named pipe(FIFO 命名管道)

    catalogue . pipe匿名管道 . named pipe(FIFO)有名管道 1. pipe匿名管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常 ...

  4. 操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

    进程通信(信号量.匿名管道.命名管道.Socket) 具体的概念就没必要说了,参考以下链接. 信号量 匿名管道 命名管道 Socket Source Code: 1. 信号量(生产者消费者问题) #i ...

  5. shell 匿名管道和命名管道

    管道的特点:如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作:同理,写入管道的操作如果没有读取管道的操作,这一动作也会滞留. 1,匿名管道 匿名管道使用 ...

  6. Linux进程间通信(四):命名管道 mkfifo()、open()、read()、close()

    在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关 ...

  7. IPC——命名管道

    Linux进程间通信——使用命名管道 转载:http://blog.csdn.net/ljianhui/article/details/10202699 在前一篇文章——Linux进程间通信——使用匿 ...

  8. Linux进程间通信——使用命名管道

    在前一篇文章——Linux进程间通信——使用匿名管道中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程 ...

  9. linux内核情景分析之命名管道

    管道是一种"无名","无形文件,只可以近亲进程使用,不可以再任意两个进程通信使用,所以只能实现"有名","有形"的文件来实现就可以 ...

随机推荐

  1. Linux升级nodejs及多版本管理

    最近要用到开发要用到nodejs,于是跑到开发机运行了下node,已经安装了,深感欣慰,是啥版本呢?再次运行了下node -v,原来是0.6.x的.估计是早先什么时候谁弄的.那么来升级下node吧. ...

  2. Spring4中@value用法详解

    版本:spring-framework-4.1 一.概述 为了简化读取properties文件中的配置值,Spring支持@Value注解的方式来获取,这种方式大大简化了项目的配置,业务中也提高了灵活 ...

  3. 【monkeyrunner】monkeyrunner 常见问题

    1.monkeyrunner和部分机型的指针位置会出现冲突 问题描述:当我们用monkeyrunner定位坐标时,会打开设置的指针位置服务.当指针位置开启时,运行monkeyrunner时,真机会出现 ...

  4. 如何查看oracle表空间是否自动扩展

    select file_name,autoextensible,increment_by from dba_data_files

  5. 黄聪:js 获取浏览器、Body、滚动条、可见区域、页面、边框、窗口高度和宽度值(多浏览器)

    IE中:document.body.clientWidth ==> BODY对象宽度document.body.clientHeight ==> BODY对象高度document.docu ...

  6. PAT 甲级 1011 World Cup Betting (20)(20 分)(水题,不用特别在乎精度)

    1011 World Cup Betting (20)(20 分) With the 2010 FIFA World Cup running, football fans the world over ...

  7. 移动自动化测试:Android Studio 、Appium、夜神模拟器

    环境是Window 10 64位 第一章:安装Appium Appium和node.js需要一起安装,他们的依赖关系暂不深究. 1. node.js傻瓜式安装 官网地址:https://nodejs. ...

  8. Jenkins迁移

    Jenkins:http://192.168.1.240:8080/jenkins 重启jenkins: sudo /etc/init.d/jenkins start sudo /etc/init.d ...

  9. RTNETLINK answers: File exists

    问题: 重启网络时报错如下 >>/etc/init.d/network start RTNETLINK answers: File exists 分析: /etc/init.d/netwo ...

  10. Unix socket的准备(一)

    套接字地址结构 套接字编程中,五元组是广为人知的. (host_ip, host_port, target_ip, target_port, protocol). 其中 ip 和 port 就是由套接 ...