totorojs / browsers

A simple and stable browser driver.
19 stars 5 forks source link

win7 下面 ie8,ie9 进程退出异常 #14

Closed leoner closed 11 years ago

leoner commented 11 years ago

现象: 如过当前已经存在运行着的 ie 浏览器,那么当通过 spawn 再次打开浏览器的时候,在 xp ,浏览器的进程句柄会被保持着,而在 win7 下面,成功打开新的浏览器后直接会触发 process 的 close 事件,而且返回码是0,但是检查 process.killed 属性是 false.说明此进程还是没有退出的。而且此进程通过 process.kill() 也无法关闭. 解决:

  1. 去除原来的重试功能,避免打开多个浏览器
  2. 通过 process.pid 和 process.killed 来确定是否通过 taskkill 来精确浏览器的进程争取的关闭。
leoner commented 11 years ago

如果是第一次打开浏览器,那么 nodejs 获取的 pid 和用系统命令查看到的 pid 是一致的。 如果已经有打开的浏览器,那么 nodejs 获取的 pid 和系统命令查看的进程的 pid 是不匹配的。 但是我们如果直接杀死第一个浏览器的 pid ,那么后面的浏览器同样会被杀死。 看样子只有了解 win7 下面浏览器加载的方式才行啊。

leoner commented 11 years ago

如果我们新打开第一个浏览器:

iexplore.exe                  2256 RDP-Tcp#0                  2     18,732 K
iexplore.exe                  2236 RDP-Tcp#0                  2     21,220 K

其中 2256 为主id. 我们后面在分别打开多个浏览器,不用关心他们的 pid 是多少。然后我们只需要执行

taskkill /pid 2256

执行一次就会杀死最后打开的那个浏览器。

leoner commented 11 years ago

关于精准的关闭某个 ie 窗口,搜索了很多,基本上没有解决方案。目前只要保证系统只维护一个浏览器管理程序,应该是没有问题。下面是一些关于这个原因的参考内容: 其中第一篇基本上最为详细了。

  1. http://answers.microsoft.com/en-us/ie/forum/ie9-windows_vista/after-closing-ie-windows-iexploreexe-processes-are/a3b1536d-1732-4f63-92d3-8fa927946d80
  2. http://answers.microsoft.com/en-us/ie/forum/ie8-windows_other/multiple-iexplore-processes/b6f6d249-d30c-4bd7-9b9b-ae647b665beb
  3. http://superuser.com/questions/55921/multiple-iexplore-exe-processing-running-in-windows-7
  4. http://www.techjunoon.com/kill-processes-from-command-prompt-in-windows-7-and-xp/
lifesinger commented 11 years ago

赞,这资料很棒。

记得有接口可以获取到窗口句柄,包括 title,是否可以通过 title 精准匹配到某个具体的 ie 窗口?

On Sat, Apr 13, 2013 at 9:46 PM, hui.kang notifications@github.com wrote:

关于精准的关闭某个 ie 窗口,搜索了很多,基本上没有解决方案。目前只要保证系统只维护一个浏览器管理程序,应该是没有问题。下面是一些关于这个原因的参考内容: 其中第一篇基本上最为详细了。

1. http://answers.microsoft.com/en-us/ie/forum/ie9-windows_vista/after-closing-ie-windows-iexploreexe-processes-are/a3b1536d-1732-4f63-92d3-8fa927946d80 2. http://answers.microsoft.com/en-us/ie/forum/ie8-windows_other/multiple-iexplore-processes/b6f6d249-d30c-4bd7-9b9b-ae647b665beb 3. http://superuser.com/questions/55921/multiple-iexplore-exe-processing-running-in-windows-7 4. http://www.techjunoon.com/kill-processes-from-command-prompt-in-windows-7-and-xp/

— Reply to this email directly or view it on GitHubhttps://github.com/totorojs/browsers-launcher/issues/14#issuecomment-16333352 .

王保平 / 玉伯(射雕) 送人玫瑰手有余香

leoner commented 11 years ago
taskkill /IM iexplore.exe /F 

目前通过额外检查系统进程,并通过上面命令,确保浏览器一定能够被关闭。

leoner commented 11 years ago

一些新的补充资料:

下面说的都是在 win7 下面,xp 下面没有此问题。

关于主进程 id的获取

tasklist /FI "imagename eq iexplore.exe"
tasklist /FI "imagename eq chrome.exe"

只要有浏览器打开,会出现2条己以上记录,其中第一条记录就是主进程的.

tasklist /FI "imagename eq firefox.exe"

比较特殊,不管打开多少个,通过上面的命名,也只会出现一条记录,也就是说子进程的 id 是无法通过这个命令获取的

子进程的关闭

taskkill /PID 主进程id

这个过程比较有意思,就是如果通过 taskkill 关闭浏览器只能通过主进程 id 来完成。每次执行一次,就会关闭最新打开的那个浏览器。

问题

taskkill /pid subId /F

通过 /F 也是能关闭的,但是:

  1. ie 会自动打开
  2. chrome 确实是把进程关闭了,但是窗口还是无法关闭 所以通过 /F 还是没有解决呀。
    • 就是我们通过 /FI 配合 Windowtitle 是可以通过标题获取某个浏览器的,但是问题还是上面的那个问题啊。
lifesinger commented 11 years ago

康辉先试试用 WMIService 能否解决问题: http://blogs.technet.com/b/heyscriptingguy/archive/2004/09/27/how-can-i-terminate-a-process-with-a-specific-pid.aspx

用微软系统自身提供的服务去操控进程,可能可行。

刚才跟沉鱼也简单讨论了一下,browsers-launcher 如果能确保浏览器自身的稳定性(launch、kill、monitor),那么与 totoro-test 的 socket 通信也可以去掉。这样各司其职,简单可靠。

  1. browsers-launcher 确保固定浏览器的稳定性。
  2. totoro-test 服务的稳定性,通过 forever 等方式自身去保证。
  3. 两者之间能不关联就不关联,除非浏览器的稳定性需要 totoro-test 提供信息。

另外一个小建议,浏览器管理服务如果保留的话,端口别用 8080,太容易和 tomcat 冲突了。

lifesinger commented 11 years ago

刚才电话里的讨论:

  1. 看能否通过 launcher 判断某个子进程失去响应,当失去响应时,整体重启就好。

这样,将问题从「精准关闭子进程」转换为:

通过 launcher 精准判断某个子进程处于失去响应状态。

如果上面的问题能解决,则不需要建立与 totoro-test 的通信,launcher 自身实现功能自完备。

「精准判断某个子进程处于失去响应状态」目前想到的可尝试思路:

  1. 通过 tasklist / ps 等系统命令,看有没有相关状态列可判断。
  2. Win 下,可尝试通过 WMIService 去判断进程状态。
lifesinger commented 11 years ago

还有一种方式是:

通过与 totoro-test 的交互来知道某个进程是否未响应了。

lifesinger commented 11 years ago

通过系统命令应该查询不到某个进程的当前状态,参考:

https://groups.google.com/forum/?fromgroups=#!topic/microsoft.public.scripting.vbscript/75jnfApmMjQ

文中提到的一个想法是:

要判断某个进程是否失去了响应,最简单有效的办法是,给该进程发消息,看它是否能继续完成新工作。

对于 browsers-launcher 来说,好像还是得通过 totoro-test 的心跳或定时来判断。

leoner commented 11 years ago

http://support.microsoft.com/kb/304991 c# 版本的实现

leoner commented 11 years ago

获取浏览器无响应状态的测试 测试方式: 通过执行一个死循环的脚本 最新测试结果:

ie9

  1. 上面提到的c# 版本的例子,确实可以获取不响应的状态
  2. 然后又看了下 powershell ,也是可以获取这个不响应的状态
  3. 最后通过 tasklist,也是可以获取这个不响应的状态的. 所以对于 ie9 可以通过多种方式获取这种不响应的状态。

ie8

ie8 会提示 停止脚本执行 的提示。这个时候

  1. 由于ie8 机器下面的 c# 的环境没有搭建,没有测试。 不过应该和 powershell 的结果是一致的。
  2. powershell 这个对于这种脚本提示下面的浏览器,获取的状态是可响应的状态
  3. tasklist 查看的也是可相应的状态 所以对于 ie8 这种提示状态是无法获取这个状态的。

chrome

直接通过 tasklist 就可以获取这种不响应的状态 1

safari

虽然浏览器操作起来比较缓慢,但是状态还是可响应的。

所以应该每个浏览器对脚本执行都有不同的策略,所以通过这种外部检测的方式,应该只能成功检查到某些浏览器,也就是这些脚本执行能够导致整个浏览器进行挂死的浏览器,但是大部分其实对这部分是有优化的,比如 ie8 的脚本停止执行的提示。看来最好的方法还是通过和外部(totoro-test)通信的方式来确定浏览器是否可相应是最靠谱的呀. 不过我们可以通过 tasklist 来检查一部分浏览器。

lifesinger commented 11 years ago

嗯,赞康辉的研究精神。我想能否这样:

  1. 通过系统命令的方式,除了 Chrome,其他浏览器看起来都不靠谱,这条路可以放弃掉。

直接与 totoro-test 通信,我的担心:

我有一个想法,不知可不可行:

  1. 在生成的 runner.html 里,载入一个 browsers-launcher.js
  2. 在 browsers-launcher 服务里,开启本地 socket
  3. 页面通过 browser-launcher.js 建立与本地 socket 服务的通信

就是本地的 launcher 通过本地的 socket 通信管理本地的 browsers

这样:

  1. browsers-launcher 与 totoro-test 并不直接关联,唯一关联是,要求 capture 的页面中有一个指定的 js
  2. browsers-launcher 是分布式的,各自管好各自,一个挂掉不影响另一个,与 totoro-test 也是解耦的

康辉看看上面的方式是否可行?

leoner commented 11 years ago

恩,我今天也是准备按照这个思路来处理呀!现在就是准备测试以下浏览器假死状态下,socket的通信的状况。如果这种方式可行的话,虽然就是 capture 的 js 有一点耦合,但是这个应该可以接受。后续测试没有问题的话,就会按照这个思路来实现呀!

lifesinger commented 11 years ago

好,期待进一步进展。

leoner commented 11 years ago

这个不在继续深入了,后续转向 #26 来处理相关问题。

fool2fish commented 11 years ago

有种柳暗花明的感觉啊,问题一下子简单了