大胖的部落格

Just a note

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  112 随笔 :: 0 文章 :: 3 评论 :: 0 Trackbacks


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、匿名管道
在父进程和子进程之间,或同一父进程的两个子进程之间传输数据的无名字的单向管道。
通常由父进程创建管道,然后由要通信的子进程继承通道的读端点句柄或写端点句柄,然后实现通信。
posted on 2009-06-17 09:55 大胖 阅读(1218) 评论(0)  编辑 收藏 引用 所属分类: Win32

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理