进程间通信有多种方法,其中常用的一种便是文件映射。
往往在不同项目中对文件映射的使用策略也不一样,这里拿一种常遇到的情况来说明需要注意的。例如:A进程(system权限)含有网络模块,负责与服务器通信,而B进程(任意用户)负责实时收集数据,由于B进程处于任意用户,不能确保它是否能与服务器通信,当不能时便要将数据给A进程处理。(条件苛刻,只能用文件映射时。)
需要注意的问题:1、高权限下创建的文件映射低权限如何打开。
2、进程间如何同步。
对于问题一,在将文件映像到内存时,CreateFileMapping中需要设置第二个参数——SECURITY_ATTRIBUTES。创建代码:
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd; //该结构不能直接修改,只能通过调用API函数来修改
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); //初始安全描述符
SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE); //设置DACL
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE; //允许句柄继承
sa.lpSecurityDescriptor = &sa;
hMap = CreateFileMapping(, &sa,...); //这样就创建了一个任意用户能打开的Map
对于第二个问题,进程间同步,A进程创建链接、关闭、发送、接收等事件对象(还会有很多),将句柄索引保存在文件映射内,并创建B进程继承句柄,创建时同样需要设置它们的SECURITY_ATTRIBUTES,给B进程提供一个虚拟网络类,当B进程需要链接服务器,便通过事件告诉A进程进行链接,其他同理。
例如A进程:
typedef struct _MAP_DATA_
{
HANLDE hCenctEvent;
HANDLE hCmpletEvent;
......
}MAP_DATA,*PMAP_DATA;
hAddress = (PMAP_DATA)MapViewOfFile(hMap, ....);
void InitMapAndEvent() {
memset(hAddress , 0, sizeof(MAP_DATA));
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE);
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = &sa;
hAddress ->hCenctEvent = CreateEvent(&sa, false, false, NULL);
hAddress ->hCmpletEvent= CreateEvent(&sa, false, false, NULL);
}
DWORD WINAPI RelConect::ConectThread(LPVOID lpParam)
{
RelConect *lp = (RelConect*)(lpParam);
if(lp == NULL) while(lp->state){
WaitForSingleObject(lp->hAddress ->hCenctEvent, INFINITE); //等待链接
//处理真实链接
SetEvent(lp->hAddress ->hCmpletEvent); //通知成功
}
}