zoukankan      html  css  js  c++  java
  • 进程间通信


    1、共享内存
    使用CreateFileMapping函数创建文件映射,指定第一个参数为INVALID_HANDLE_VALUE表明在系统页文件中开辟共享内存,最后一个参数指定文件映射的名字。
    使用MapViewOfFile将已创建的文件映射映射到当前进程地址空间,可以读写访问。

    另一个进程可以使用OpenFileMapping通过制定文件映射名字,打开一个已经创建的文件映射。
    使用MapViewOfFile将已创建的文件映射映射到当前进程地址空间,可以读写访问。

    这样两个进程都可以讲共享内存映射到自己的进程地址空间,进行通信。
    通信完毕后需要使用UnmapViewOfFile取消映射,CloseHandle销毁文件映射。
    只适用于同一机器上的进程间通信。

    写数据的进程:

    #include <iostream>
    #include 
    <windows.h>
    #include 
    <process.h>
    using namespace std;



    int main()
    {
        
    //创建文件映射,指向操作系统页面文件
        HANDLE hFileMapping = ::CreateFileMapping((HANDLE)INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0sizeof(int), "TestMem");

        
    //将共享内存映射到当前进程地址空间
        int* addr = (int*)::MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 00sizeof(int));
        
        
    //向共享内存中写数据
        *addr = 23;
        getchar();

        
    //解除共享内存到当前进程地址空间的映射
       :: UnmapViewOfFile(addr);

        
    //销毁文件映射
        ::CloseHandle(hFileMapping);
        
    return 0;
    }


    读数据的进程:
    #include <iostream>
    #include 
    <windows.h>
    #include 
    <process.h>
    using namespace std;



    int main()
    {
        
    //打开一个已命名的文件映射
        HANDLE hFileMapping = ::OpenFileMapping(FILE_MAP_READ, false"TestMem");

        
    //将其映射到进程地址空间
        int* addr = (int*)::MapViewOfFile(hFileMapping, FILE_MAP_READ, 00sizeof(int));
        
        
    //读取共享内存中的数据
        cout<<*addr<<endl;
        getchar();


        
    //解除到进程地址空间的映射
        :: UnmapViewOfFile(addr);

        
    //关闭文件映射
        ::CloseHandle(hFileMapping);
        
    return 0;
    }





    2、命名管道
    服务器是唯一一个有权创建命名管道的进程,也只有它才能接受管道客户机的连接请求。
    对一个客户机应用来说,它只能同一个已命名的管道服务器建立连接。
    在客户机和服务器之间,一旦建好连接,两个进程都能对标准的Win32函数,在管道上进行数据的读取与写入。这些函数包括ReadFile和WriteFile等等。
    命名管道的命名格式:   //ServerName/Pipe/PipeName
    其中ServerName是服务器名字,Pipe固定表示管道,PipeName是管道名称。
    命名管道适用于单机或网络进程间通信。

    服务器端
    #include <iostream>
    #include 
    <windows.h>
    #include 
    <process.h>
    using namespace std;



    int main()
    {
        
    //创建一个命名管道
        HANDLE hPipe = ::CreateNamedPipe("////.//pipe//MyPipe", PIPE_ACCESS_DUPLEX, 02000, NULL);

        
    //将服务器端连接到命名管道,并监听是否有客户端连接到已创建的命名管道,若有则返回
        ::ConnectNamedPipe(hPipe, NULL);

        
    //从管道中读数据
        char cBuffer[1024= {0}
        DWORD dwSize 
    = 0;
        ::ReadFile(hPipe, cBuffer, 
    1024&dwSize, NULL);
        cout
    <<cBuffer<<endl;

        
    //断开服务器端与命名管道的连接
        ::DisconnectNamedPipe(hPipe);

        
    //销毁管道
        ::CloseHandle(hPipe);
        
    return 0;
    }


    客户端
    #include <iostream>
    #include 
    <windows.h>
    #include 
    <process.h>
    using namespace std;



    int main()
    {
        
    //客户端等待,直到指定的命名管道可用
        ::WaitNamedPipe(L"////.//pipe//MyPipe", NMPWAIT_WAIT_FOREVER);

        
    //创建一个命名管道的实例
        HANDLE hPipe = ::CreateFile(L"////.//pipe//MyPipe", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        
    //写数据
        const char* cWrite = "test pipe";
        DWORD dwSize 
    = 0;
        ::WriteFile(hPipe, cWrite, (DWORD)strlen(cWrite)
    +1&dwSize, NULL);

        
    //关闭管道
        ::CloseHandle(hPipe);
        
    return 0;
    }





    3、邮件槽
    邮件槽(Mailslots)提供进程间单向通信能力,服务器端创建邮件槽,客户端通过名字连接邮件槽,同一个邮件槽只允许客户端向服务器端发送数据。
    邮件槽命名与命名管道类似。
    支持单机或不同计算机之间的进程间通信。

    服务器端
    #include <iostream>
    #include 
    <windows.h>
    #include 
    <process.h>
    using namespace std;



    int main()
    {
        
    //创建一个邮件槽
        
    //第三个参数若为0,ReadFile即使读不到数据也立刻返回;若为MAILSLOT_WAIT_FOREVER,ReadFile将等待知道读到数据
        HANDLE hMail = ::CreateMailslot("////.//mailslot//MyMail"0, MAILSLOT_WAIT_FOREVER, NULL);

        
    //从邮件槽中读数据
        char cBuffer[1024= {0}
        DWORD dwSize 
    = 0;
        ::ReadFile(hMail, cBuffer, 
    1024&dwSize, NULL);
        cout
    <<cBuffer<<endl;

        
    //销毁邮件槽
        ::CloseHandle(hMail);
        
    return 0;
    }


    客户端
    #include <iostream>
    #include 
    <windows.h>
    #include 
    <process.h>
    using namespace std;



    int main()
    {
        
    //打开一个已命名的邮件槽
        
    //第二个参数必须设为GENERIC_WRITE,因为客户机只能向服务器写入数据。
        
    //第三个参数必须设为FILE_SHARE_READ,允许服务器在邮槽上打开和进行读操作。
        HANDLE hMail = ::CreateFile(L"////.//mailslot//MyMail", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

        
    //写数据
        const char* cWrite = "test mail";
        DWORD dwSize 
    = 0;
        ::WriteFile(hMail, cWrite, (DWORD)strlen(cWrite)
    +1&dwSize, NULL);

        
    //关闭邮件槽
        ::CloseHandle(hMail);
        
    return 0;
    }




    4、socket连接
    服务器端和客户端通过socket连接通信,适用于网络间进程通信。

    服务器端
    #include <iostream>
    #include 
    <winsock.h>
    #pragma comment (lib, 
    "Ws2_32.lib")

    using namespace std;


    int main()
    {
        
    //初始化使用socket函数要用到的dll
        WSADATA wd;
        ::WSAStartup(MAKEWORD(
    2,2), &wd);

        
    //本机地址信息
        sockaddr_in addr;
        addr.sin_family            
    = AF_INET;
        addr.sin_port            
    = htons(1555);
        addr.sin_addr.s_addr    
    = inet_addr("127.0.0.1");

        
    //创建套接字,并与本机地址绑定
        SOCKET s = ::socket(AF_INET, SOCK_STREAM, 0);
        ::bind(s, (
    const sockaddr*)&addr, sizeof(addr));
        
        
    //监听该套接字,准备接收连接
        ::listen(s, 2);

        
    //等待客户端连接,若客户端连接则返回,否则一直等待
        
    //返回结果是用来通信的新套接字
        sockaddr_in client_addr;
        SOCKET ns 
    = ::accept(s, (sockaddr*)&client_addr, NULL);

        
    //在新套接字上收数据
        while(1)
        
    {
            
    char cBuffer[1024= {0};
            ::recv(ns, cBuffer, 
    10240);
            cout
    <<cBuffer<<endl;
        }


        
    //关闭套接字
        ::closesocket(ns);
        ::closesocket(s);

        
    //ws2.dll的收尾工作
        ::WSACleanup();

        
    return 0;
    }


    客户端
    #include <iostream>
    #include 
    <winsock.h>
    #pragma comment (lib, 
    "Ws2_32.lib")

    using namespace std;


    int main()
    {
        
    //初始化使用socket函数要用到的dll
        WSADATA wd;
        WSAStartup(MAKEWORD(
    2,2), &wd);

        
    //服务器地址信息
        sockaddr_in addr;
        addr.sin_family            
    = AF_INET;
        addr.sin_port            
    = htons(1555);
        addr.sin_addr.s_addr    
    = inet_addr("127.0.0.1");

        
    //创建套接字,并与服务器连接
        SOCKET s = ::socket(AF_INET, SOCK_STREAM, 0);
        ::connect(s, (
    const sockaddr*)&addr, sizeof(addr));

        
    //发送数据
        while(1)
        
    {
            
    char cData[1024= {0};
            cin
    >>cData;
            ::send(s, cData, (
    int)strlen(cData)+10);
        }


        
    //关闭套接字
        ::closesocket(s);

        
    //ws2.dll的收尾工作
        ::WSACleanup();

        
    return 0;
    }




    5、dll共享数据段
    动态链接库被加载后,映射到各自进程地址空间,但位于共享数据段内的变量为所有加载该dll的进程所共享。
    把需要共享的数据变量放入自定义的数据段中, 需要初始化的变量放入   #pragma   data_seg()定义的数据段中;不需初始化的变量放入#pragma   bss_seg()定义的数据段中。
    然后打开/SECTION 开关,请连接器为这些数据段定义共享属性。
      
    dll文件
    //共享数据段
    #pragma data_seg("Shared"
    __declspec(dllexport) 
    char g_SharedBuffer[1024= {0}
    #pragma data_seg() 

    #pragma comment(linker, 
    "/Section:Shared,rws")

    //非共享数据段
    __declspec(dllexport) char g_Buffer[1024= {0}

    进程1写数据
    #include <iostream>
    #pragma comment (lib, 
    "..//..//dll//release//dll")

    using namespace std;


    int main()
    {
        
    //导入dll中的变量
        __declspec(dllimport) char g_Buffer[];
        __declspec(dllimport) 
    char g_SharedBuffer[];

        
    //分别向两个变量中写入数据
        strcpy(g_Buffer, "not shared");
        strcpy(g_SharedBuffer, 
    "shared");

        cout
    <<g_Buffer<<endl;
        cout
    <<g_SharedBuffer<<endl;

        getchar();
        
    return 0;
    }


    进程2读数据
    #include <iostream>
    #pragma comment (lib, 
    "..//..//dll//release//dll")

    using namespace std;


    int main()
    {
        
    //导入dll中的变量
        __declspec(dllimport) char g_Buffer[];
        __declspec(dllimport) 
    char g_SharedBuffer[];

        
    //输出结果
        cout<<g_Buffer<<endl;            //非共享数据段内的变量没有进程1写的值
        cout<<g_SharedBuffer<<endl;        //共享数据段内的变量读出了进程1写的值

        getchar();
        
    return 0;
    }



    6、WM_COPYDATA消息
    发送方只需使用调用SendMessage函数,参数是目的窗口的句柄、传递数据的起始地址、WM_COPYDATA消息。
    接收方只需像处理其它消息那样处理WM_COPY DATA消息,这样收发双方就实现了数据共享。

    7、剪切板

    8、匿名管道
    在父进程和子进程之间,或同一父进程的两个子进程之间传输数据的无名字的单向管道。
    通常由父进程创建管道,然后由要通信的子进程继承通道的读端点句柄或写端点句柄,然后实现通信。

  • 相关阅读:
    powerDesigner生成Html及Word
    MySQL中information_schema是什么
    使用Navicat快速生成数据库字典
    SpringBoot学习:使用spring-boot-devtools进行热部署
    ajax 把返回结果作为参数传递
    application.properties详解 --springBoot配置文件
    intellij idea 无法启动或调试 spring-boot
    mybatis添加记录时返回主键id
    springboot form 提交集合 list
    表单提交之List集合
  • 原文地址:https://www.cnblogs.com/marryZhan/p/2213927.html
Copyright © 2011-2022 走看看