邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自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[100];
        DWORD dwRead;
    
        //创建邮槽
        hMailslot=CreateMailslot("\\\\.\\mailslot\\Communication",0,
            MAILSLOT_WAIT_FOREVER,NULL);
        if(INVALID_HANDLE_VALUE==hMailslot)
        {
            cout<<"创建邮槽失败!"<<endl;
            system("pause");
            return;
        }
    
        //等待用户写入数据然后读取出数据
        if(!ReadFile(hMailslot,buf,100,&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)+1,&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[100];
        DWORD dwRead;
    
        //创建匿名管道
        sa.bInheritHandle=TRUE;
        sa.lpSecurityDescriptor=NULL;
        sa.nLength=sizeof(SECURITY_ATTRIBUTES);
        if(!CreatePipe(&hRead,&hWrite,&sa,0))
        {
            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(2000);
    
            //读取数据
            if(!ReadFile(hRead,rebuf,100,&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[100];
        DWORD dwWrite;
    
        //写入数据
        if(!WriteFile(hWrite,sebuf,strlen(sebuf)+1,&dwWrite,NULL))
        {
            cout<<"写入数据失败!"<<endl;
            system("pause");
            return;
        }
        Sleep(500);
    
        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[100];
    
        /*创建命名连接*****************************************************/
        hPipe=CreateNamedPipe("\\\\.\\pipe\\Communication",
            PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
            0,1,1024,1024,0,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,100,&dwRead,NULL))
        {
            cout<<"读取数据失败!"<<endl;
            system("pause");
            return;
        }
        cout<<rebuf<<endl;
    
        //写入数据
        if(!WriteFile(hPipe,sebuf,strlen(sebuf)+1,&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[100];
    
        /*连接管道连接*****************************************************/
        if(!WaitNamedPipe("\\\\.\\pipe\\Communication",NMPWAIT_WAIT_FOREVER))
        {
            cout<<"当前没有可利用的命名管道实例!"<<endl;
            system("pause");
            return;
        }
    
        /*打开管道连接*****************************************************/
        hPipe=CreateFile("\\\\.\\pipe\\Communication",GENERIC_READ | GENERIC_WRITE,
            0,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)+1,&dwWrite,NULL))
        {
            cout<<"写入数据失败!"<<endl;
            system("pause");
            return;
        }
    
        //读取数据
        if(!ReadFile(hPipe,rebuf,100,&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()+1);
            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");
    }

     

  • 运行结果:

时间: 2024-10-12 21:57:28

邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自http://www.cnblogs.com/kzloser/archive/2012/11/04/2753367.html#的相关文章

性能分析:处理器、磁盘I/O、进程、网络分析方法 http://www.cnblogs.com/fnng/archive/2012/10/30/2747246.html

------windows操作系统 windows系统下的计数器比较多,主要技术器如下: CPU分析                                                                                          那么我们CPU性能最直接的评估就是查看其CPU工作频率,就是CPU的时钟频率,单位为是Hz.随着CPU的发展,主频由MHz现在的GHz (1GHz=1000MHz=1000000KHz=1000000000Hz) 处理器

进程间的通信——邮槽与命名管道d

进程间的通信是指在系统中两个或多个进程之间通过第三方进行数据共享. 1.邮槽. 邮槽是window系统提供的一种单向通信的机制.即进程中的一方只能写入或者读取数据,而另一方则只能读取或写入数据.通过邮槽,可以实现一对多或跨网络的进程之间的通信.但邮槽传输的数据量非常小,一般只有400KB左右. 邮槽创建函数CreateMailslot,函数原型: HANDLE CreateMailslot( LPCTSTR lpName, // mailslot name DWORD nMaxMessageSi

使用命名管道进程之间通信(转)

原文地址:http://www.cnblogs.com/yukaizhao/archive/2011/08/04/system-io-pipes.html 命名管道: 命名管道的功能比匿名管道更强大,可以在进程之间做双工通信(即通信的两个进程都是既可以读也可写的):命名管道也可以实现跨网络在不同机器之间进行通信.可以在多线程中创建多个NamedPipeServerStream实例,为多个client端服务.另外命名管道还支持消息传输,这样client端可以读取任意长度的消息,而无须知道消息的长度

命名管道跨进程通信实例2(转)

原文:http://www.cnblogs.com/jonneydong/archive/2012/03/02/2418743.html 服务端代码: //创建服务端,管道实例 NamedPipeServerStream serverStream = new NamedPipeServerStream("test2PIPE", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);

Linux进程间通信 -- 使用命名管道

在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程之间交换数据带来了不方便.这里将会介绍进程的另一种通信方式——命名管道,来解决不相关进程间的通信问题. 一.什么是命名管道 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似. 由于Linux中所有

进程间通信——命名管道

概念 管道一个不足之处是没有名字,因此只能用于具有亲缘关系的进程间通信,命名管道(named pipe或FIFO)解决了这一问题. FIFO提供一个路径名与之关联,以FIFO文件的形式存储于文件系统中.文件系统中路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道. 对文件系统来说,匿名管道(管道)是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信.而命名管道是一个可见的文件,因此,他可以用于任意两个进程间进行通信,不管这两个进程是不是父子进程,也不管这两

IPC——命名管道

Linux进程间通信——使用命名管道 转载:http://blog.csdn.net/ljianhui/article/details/10202699 在前一篇文章——Linux进程间通信——使用匿名管道中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程之间交换数据带来了不方便.这里将会介绍进程的另一种通信方式——命名管道,来解决不相关进程间的通信问题. 一.什么是命名管道 命名管道也被称为FIF

Linux进程间通信(IPC)编程实践(二) FIFO命名管道

在前一篇文章中,我们讲解了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程之间交换数据带来了不方便.这里将会介绍进程的另一种通信方式--命名管道,来解决不相关进程间的通信问题. 什么是命名管道 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似. 由于Linux中所有的事物都可被视为文件,所以对命名管道的使用也就变得与

使用命名管道实现进程间通信

创建命名管道 命名管道常常用于应用程序之间的通迅,由于不需要进行序列化和反序列化操作,效率是非常高的.相比TCP通信方式,效率更高,但比共享内存要低点.命名管道可以在本地机器或者局域网内机器实现进程间通信,所以是最佳的通信方式. 创建一个NamedPipeServerStream: NamedPipeServerStream pipeServer = new NamedPipeServerStream(_pipName, PipeDirection.InOut, 10); 这里表示命名管道服务器