当前位置:  开发笔记 > 前端 > 正文

如何将X11窗口ID转换为进程ID

如何解决《如何将X11窗口ID转换为进程ID》经验,为你挑选了2个好方法。

我正在处理一个小应用程序,我需要找到给定其主窗口或子窗口的X11窗口ID的进程的PID.我看到了使用这种转换的示例_NET_WM_PID,但我无法弄清楚如何在不使用它的情况下执行此操作.不使用的原因_NET_WM_PID是它没有在所有可用的窗口管理器中实现,我的应用程序需要处理它们中的任何一个(或至少在大多数窗口管理器上).有人可以帮助我,并就如何解决这个问题给我一些建议/指示?谢谢!



1> 小智..:

除非你的X-服务器支持XResQueryClientIds来自X-资源V1.2扩展我知道有没有简单的方法来可靠地请求进程ID.然而还有其他方法.

如果你面前有一个窗口而且还不知道它的ID - 很容易找到它.只需在相关窗口旁边打开一个终端xwininfo,然后在那里运行并单击该窗口.xwininfo会告诉你window-id.

所以我们假设您知道一个window-id,例如0x1600045,并且想要查找拥有它的进程是什么.

检查该窗口所属的最简单方法是运行XKillClient,即:

xkill -id 0x1600045

看看刚刚死去的过程.当然如果你不介意它会死.

另一种简单而可靠的方法是检查它_NET_WM_PIDWM_CLIENT_MACHINE属性:

xprop -id 0x1600045

这就是工具喜欢xlsclientsxrestop做的事情.

不幸的是,这些信息可能不正确,不仅因为这个过程是邪恶的并且改变了这些信息,而且还因为它是错误的.例如,在一些firefox崩溃/重启之后,我已经看到孤立的窗口(我猜是来自flash插件)_NET_WM_PID指向一个很久以前就已经死亡的进程.

另一种方式是运行

xwininfo -root -tree

并检查有问题的窗口的父母的属性.这也可能会给你一些关于窗口起源的提示.

但!虽然您可能找不到创建该窗口的进程,但仍有一种方法可以找到该进程从哪里连接到X-server.这种方式适用于真正的黑客.:)

您知道的低位(即0x1600000)的窗口ID 0x1600045是"客户端基础".并且为该客户端分配的所有资源ID都基于它(0x1600001,0x1600002,0x1600003等).X-server在clients []数组中存储有关其客户端的信息,对于每个客户端,其"base"存储在clients [i] - > clientAsMask变量中.要查找对应于该客户端的X-socket,需要连接到X-server gdb,遍历clients []数组,找到客户端clientAsMask并打印其套接字描述符,存储在((OsCommPtr)(clients [i] - > osPrivate)) - > FD.

可能有许多X客户端连接,所以为了不手动检查它们,让我们使用gdb函数:

define findclient
  set $ii = 0
  while ($ii < currentMaxClients)
    if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
      print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
    end
    set $ii = $ii + 1
  end
end

当您找到套接字时,您可以检查,谁连接到它,最后找到该过程.

警告:不要从X-server的INSIDE将gdb附加到X-server.gdb挂起它附加的进程,所以如果从X-session内部附加到它,你将冻结你的X服务器,并且无法与gdb交互.您必须切换到文本终端(Ctrl+Alt+F2)或通过ssh连接到您的计算机.

例:

    找到X服务器的PID:

    $ ps ax | grep X
     1237 tty1     Ssl+  11:36 /usr/bin/X :0 vt1 -nr -nolisten tcp -auth /var/run/kdm/A:0-h6syCa
    

    窗口ID为0x1600045,因此客户端基数为0x1600000.连接到X-server并查找该客户端的客户端套接字描述符.您需要为X-server安装调试信息(rpm分发的-debuginfo包或deb的-dbg包).

    $ sudo gdb
    (gdb) define findclient
    Type commands for definition of "findclient".
    End with a line saying just "end".
    >  set $ii = 0
    >  while ($ii < currentMaxClients)
     >   if (clients[$ii] != 0 && clients[$ii]->clientAsMask == $arg0 && clients[$ii]->osPrivate != 0)
      >     print ((OsCommPtr)(clients[$ii]->osPrivate))->fd
      >     end
     >   set $ii = $ii + 1
     >   end
    >  end
    (gdb) attach 1237
    (gdb) findclient 0x1600000
    $1 = 31
    (gdb) detach
    (gdb) quit
    

    现在您知道客户端已连接到服务器套接字31. lsof用于查找该套接字的内容:

    $ sudo lsof -n | grep 1237 | grep 31
    X        1237    root   31u   unix 0xffff810008339340       8512422 socket
    

    (这里"X"是进程名称,"1237"是它的pid,"root"是它运行的用户,"31u"是套接字描述符)

    在那里你可能会看到客户端通过TCP连接,然后你可以转到它连接的机器并检查netstat -nap那里以找到进程.但很可能你会在那里看到一个unix socket,如上所示,这意味着它是一个本地客户端.

    要找到该unix套接字的一对,您可以使用MvG的技术 (您还需要安装内核的调试信息):

    $ sudo gdb -c /proc/kcore
    (gdb) print ((struct unix_sock*)0xffff810008339340)->peer
    $1 = (struct sock *) 0xffff810008339600
    (gdb) quit
    

    既然你知道客户端套接字,用于lsof查找保存它的PID:

    $ sudo lsof -n | grep 0xffff810008339600
    firefox  7725  username  146u   unix 0xffff810008339600       8512421 socket
    

而已.保持该窗口的进程是"firefox",进程号为7725



2> Martin v. Lö..:

通常,不可能找到创建窗口的进程的PID.可能是该进程在机器上远程运行,并且可能是机器甚至没有进程和PID的概念.

如果您在最初创建客户端时不信任任何人存储此信息,则您需要自己跟踪连接.找出客户端使用的连接类型(套接字等),找出连接结束的位置,并找出结束的过程.如何做到(以及是否可能)是高度依赖操作系统的.


在什么编程环境中?"xprop -id wid _NET_WM_PID"应该这样做.
推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有