邮槽

通信流程:

  • 服务器

  • 客户端

  • 注意:

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

    You are given array a a of length n n . You can choose one segment [l,r] [l,r] (1≤l≤r≤n 1≤l≤r≤n ) an ...

  2. bzoj 2212 Tree Rotations

    bzoj 2212 Tree Rotations 考虑一个子树 \(x\) 的左右儿子分别为 \(ls,rs\) .那么子树 \(x\) 内的逆序对数就是 \(ls\) 内的逆序对数,\(rs\) 内 ...

  3. HDU 1285:确定比赛名次(拓扑排序)

    确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  4. Web Server部署架构图

    一.整体架构图 二.框架的瓶颈 上述框架的瓶颈在存储NFS,现在较多的使用的是GFS分布式存储

  5. html页面下拉列表中动态添加后台数据(格式化数据,显示出数据的层次感)

    html页面下拉列表中动态添加后台数据(格式化数据,显示出数据的层次感) 效果图: 运行原理和技术: 当页面加载完毕,利用jquery向后台发送ajax请求,去后台拼接<select>&l ...

  6. CH1809 匹配统计

    题意 描述 阿轩在纸上写了两个字符串,分别记为A和B.利用在数据结构与算法课上学到的知识,他很容易地求出了"字符串A从任意位置开始的后缀子串"与"字符串B"匹配 ...

  7. ES6必知必会 (九)—— Module

    Module 1.ES6在语言标准的层面上,实现了模块功能,成为浏览器和服务器通用的模块解决方案,完全可以取代 CommonJS 和 AMD 规范,基本特点如下: 每一个模块只加载一次, 每一个JS只 ...

  8. /etc/fstab和/etc/mtab

    一./etc/fstab和/etc/mtab的区别 1./etc/fstab /etc/fstab是开机自动挂载的配置文件,在开机时起作用.相当于启动linux的时候,自动使用检查分区的fsck命令和 ...

  9. oracle/ms sql 系统表

    sql server系统表详细说明 sysaltfiles 主数据库 保存数据库的文件 syscharsets 主数据库字符集与排序顺序 sysconfigures主数据库 配置选项 syscurco ...

  10. MySql-5.7.17 -winx64的安装配置

    一.下载软件 1. 进入mysql官网,登陆自己的Oracle账号(没有账号的自己注册一个),下载Mysql-5.7.17,下载地址:http://dev.mysql.com/downloads/my ...