龙空技术网

向子进程传递大量数据的方法

漫漫开发路 716

前言:

当前朋友们对“进程间传递大量数据用什么实现比较好”大约比较关切,同学们都需要剖析一些“进程间传递大量数据用什么实现比较好”的相关知识。那么小编在网络上搜集了一些有关“进程间传递大量数据用什么实现比较好””的相关资讯,希望大家能喜欢,小伙伴们快快来学习一下吧!

如何传递大型数据给子进程

昨天的一篇文章中,我们说到如果想向一个子进程传输多于32767个字符的数据,我们需要寻找其他的方法(而不是命令行参数)来实现。

我们能想到的第一个方法是:WM_COPYDATA。当子进程创建并进入消息循环后,我们使用FindWindow来寻找进程的窗口并发送WM_COPYDATA消息。但是,这种方法有几个问题:

> 你需要寻找一种方法确定子进程确实已经创建了目标窗口并进入消息循环,这样才可以进行窗口查找。(提示:可以使用WaitForInputIdle这个方法)

> 你需要确保我们使用FindWindow查找到的窗口确实是你希望得到的那个,因为如果其他进程的窗口碰巧也有相同的标题或者窗口类,则你可能得到的不是目标窗口。又或者,有多个相同的子进程实例,也会创建同样的窗口实例。所以,你需要确定查找到正确的目标窗口。(提示:可以使用GetWindowThreadProcessId这个方法)

> 你需要确保其他人不会查找到你的窗口并在你之前发送WM_COPYDATA,如果他们这样做了,那他们就得到了你的子进程的控制权了。

> 子进程需要设计一种机制,来对抗一些恶意进程发送伪造的WM_COPYDATA消息,并尽可能正确处理它们(丢弃这种请求)。

我所推荐的方法是:匿名共享内存

基本想法是,创建一块共享内存并填充你需要传输的数据。然后将它的句柄设置为可继承的,然后创建子进程,传输句柄的数字表示到子进程的命令行。

子进程会从命令行中得到这个句柄,并映射这块共享内存到它的进程空间,这样就能访问到你传递给它的数据了。

关于这种方法的几点说明:

> 子进程需要判断句柄的有效性,防止某些人传递一些无效的或者伪造的数据。

> 如果恶意进程想搞乱你的子进程命令行,则它们必须拥有PROCESS_VM_WRITE权限。如果它们想访问进程句柄表,则还需要有PROCESS_DUP_HANDLE权限。这些都是安全的访问掩码,所有配置合适的ACL可以起到很好的保护作用。(默认的ACL就可以起到保护,所以使用默认的ACL就行了)

> 在这种方法中,没有名字和数字可以被恶意进程监听或者伪造。前提是你对子进程实施了PROCESS_VM_WRITE和PROCESS_DUP_HANDLE保护。

> 因为我们使用的是共享内存,所以共享的数据不会真正地在两个进程之间拷贝,它们只是被操作系统重新映射而已。对于传输大型数据来说,这种方法十分高效。

在下面的例子代码中,我们演示了如何使用共享内存技术来传输数据。

在实际的项目中,上面的STARTUPPARAMS结构体的成员可能会十分复杂,但是出于演示目的,我在这里仅仅定义了一个整数成员。

CreateStartupParams创建了一个在共享内存区中的STARTUPPARAMS的结构体。首先,我们填充SECURITY_ATTRIBUTES结构体并将它的可继承属性设置为TRUE,这样子进程就可以访问到这块共享内存。将lpSecurityDescriptor设置为NULL表明我们希望使用默认的安全描述符,我们使用这个默认的值就够了。然后,我们创建了一个指定大小的共享内存对象,然后将它映射到内存,最后,我们返回了一个共享内存的句柄和映射后的内存地址。

GetStartupParams函数是与CreateStartupParams对应的函数。它从命令行上解析出句柄的值并尝试进行内存映射。如果句柄不是一个合法的文件映射句柄,则MapViewOfFile调用会失败,我们可以通过这种方法进行参数的有效性校验。然后,我们使用了VirtualQuery来查询内存映射区的大小。(这里,我们没有使用更加严格的测试方法,因为它的返回值可能被舍入到最近的页边界)

我们还需要释放共享内存来防止可能出现的内存泄露,所以我们定义了上面的FreeStartupParams函数实现这一点。

上面的函数中,我们主要是构建子进程的命令行参数。我们使用了GetModuleFileName(NULL)来获取执行程序的全路径,然后传输句柄的数字表示,并在调用CreateProcess时设置了参数TRUE来表明我们希望子进程的句柄是可以继承的。

有一个小地方需要注意的:我们使用了引号来处理程序路径中含有空格的情况。

最后,我们将上面所有的程序片段组合在一起。

如果命令行上已经有一个参数了,表明这次运行的是子进程,所以我们将这个参数转换为STARTUPPARAMS并获取其中的数据并显示出来。

如果命令行上没有传递参数,则表明我们运行的是父进程,在这种情况下,我们创建了一个STARTUPPARAMS,并设置我们需要传输的数据(这里使用了42作为例子),然后传输给子进程。

总结

今天我们演示了如何向子进程传输大量数据的方法,虽然在上面的例子中,我们传递的数据量很小,但是如果稍加改进,完全可以实现传递大型数据。

所以各位老哥,可以将这种方法,稳稳地放到你的技能工具箱了。

标签: #进程间传递大量数据用什么实现比较好