如何找到断开连接的 xrdp 会话?

如何找到断开连接的 xrdp 会话?

我这里有一个 Xubuntu 14.04 服务器,它运行 xrdp,以便让几个用户连接到它。
现在有一个问题:通过 RDP 从 Windows 瘦客户端访问此服务器的用户经常使用“X”关闭 RDP 会话(因此断开连接但不注销)。

我知道 sesman.ini 中有一些选项可以处理这种行为,但正如手册页所说,这些选项目前被忽略了(并且已经忽略了好几年)。
可以解决我的问题的选项是:
KillDisconnected
DisconnectedTimeLimit
IdleTimeLimit

现在我需要破解一些处理断开连接的会话的东西。我的第一个想法是杀死所有断开连接的远程用户 - 但我不知道如何获取哪些会话已断开的信息。

那么...我如何找到断开连接的会话?
或者:是否有任何首选方法来处理断开连接的会话?

答案1

以下是获取已断开连接的 xrdp 会话列表的方法。它依赖于偏磷酸钠在正常的 X 会话管理器使用中,服务器是唯一与虚拟主机X Window System 显示服务器。当 xrdp 会话处于活动状态时,关联的 Xvnc 显示服务器有两个 TCP 连接,一个处于 ESTABLISHED 状态,另一个处于 LISTEN 状态。这看起来像这样使用lsof(1)程序。

$ sudo lsof  -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
Xvnc    1625 guest    1u  IPv4 252910      0t0  TCP 127.0.0.1:5910 (LISTEN)
Xvnc    1625 guest    9u  IPv4 261226      0t0  TCP 127.0.0.1:5910->127.0.0.1:35242 (ESTABLISHED)

如果远程会话的用户通过关闭 RDP 连接(或者,在 Apache Guacamole RDP 会话的情况下,通过关闭浏览器窗口)放弃它,它看起来像这样:

COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
Xvnc    1625 guest    1u  IPv4 252910      0t0  TCP 127.0.0.1:5910 (LISTEN)

请注意,此断开连接的 Xvnc 显示服务器进程上没有已建立的连接。因此,任何仅处于监听状态的 Xvnc 进程都是断开连接的会话。

以下是一个 shell 脚本(名为lsdisconnected),用于显示每个断开连接的远程会话的 PID 和 USER。它使用lsof(1)呆呆(1)实现连接逻辑。

#!/bin/bash
sudo lsof -FRgpLT -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999  |
gawk '
      match($0,/^p([0-9]+)/,       p) {pid = p[1]; pids[pid]=0; } ;
      match($0,/^L([A-Za-z0-9]+)/, p) {user[pid] = p[1]; } ;
      /TST=LISTEN/ {pids[pid] = pids[pid] - 1 ;};
      /TST=ESTABLISHED/{pids[pid] = pids[pid] + 1};
      END {
          for (pid in pids){
              if (pids[pid] < 0) {
                  print pid, user[pid];
              }
          }};
     '

这是查找断开的远程桌面会话的便捷方法;它在断开连接后立即工作,而无需使用空闲时间。

对于那些可能不熟悉lsof(1)以下是本示例中命令行参数的解释。

  • -b -w避免 lsof 内核等待。这里不需要它们。
  • -n避免对主机名进行 DNS 查找。
  • -c /^Xvnc$/b使用正则表达式查找具有精确命令名称 Xvnc 的进程。
  • -a告诉 lsof 在过滤时使用 AND,而不是 OR。
  • -iTCP:5900-5999按 T​​CP 端口号 5900 - 5999 进行过滤,这些端口用于 X 显示连接。

答案2

我终于找到了解决办法。
首先,我必须安装一个名为的小程序xprintidle

sudo apt-get install xprintidle

之后我编写了一个小型 bash 脚本,首先获取 Xvnc 和 xrdp 使用的所有显示器,然后检查这些显示会话是否空闲了几分钟:

#!/bin/bash

displays=`ps aux | grep Xvnc | grep -v 'grep\|sed' | sed -r 's|.*(Xvnc :[0-9]*).*|\1|' | cut -d' ' -f 2`
limit=180


date
echo "Checking for inactive sessions!"
while read -r d; do
    export DISPLAY=$d
    idle=`xprintidle`
    idleMins=$(($idle/1000/60))
    if [[ $idleMins -gt $limit ]]; then
        echo "WARN Display $d is logged in for longer than ${limit}min (${idleMins}m)"
    else
        echo "INFO Display $d is still ok (${idleMins}m)"
    fi  
done <<< "$displays"

答案3

旧帖子,但我遇到了同样的问题:sesman.ini 中的参数 KillDisconnected/DisconnectedTimeLimit/IdleTimeLimit 在 Xvnc 中不起作用。

一个简单的解决方案是将这些参数添加到 sesman.ini 中的 [Xvnc] 段落中:

paramX=-MaxDisconnectionTime
paramX=3600

(X 取决于已定义的参数数量)

这样,断开的会话将在 1 小时后自动终止。

答案4

感谢 -fu lsof!检测“死”Xvnc会话一直是 的一个长期问题Xrdp。我已将 O. Jones 的代码合并到一个 shell 脚本中,该脚本可以在启动时加载并从屏幕运行,以清理用户关闭 RDP 窗口或连接因任何原因断开时留下的死进程。我从未找到处理此问题的Xvnc方法,所以这个代码很完美。Xrdplsof

#!/bin/bash

#
# this could be launched from rc.local via screen
#   echo '/usr/bin/screen -dmS xrdp_cleanup /root/bin/xrdp_cleanup_discod_sessions' | at now
#
while [ 1 ]; do
   # loop through all listening Xvnc processes and make sure there's an established connection
   for pid in `lsof -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 | grep L[I]STEN | awk '{print $2};'`; do

      # new sessions may take a second or two on busy systems. 
      # wait for new LISTEN sessions to be become established. this also acts as a throttle for the loop
      sleep 2

      # get user for the established session
      euser=`lsof -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 | grep L[I]STEN | grep "$pid" | awk '{print $3};'`
      esta=`lsof -b -w -n -c /^Xvnc$/b -a -iTCP:5900-5999 | grep E[S]TABLISHED | grep "$pid" | awk '{print $2};'`

      test -z "$euser" && echo "Unable to find user in lsof output!"

      if [ -n "$esta" ]; then
         # regular status update
         echo "user $euser has an established sesson on pid $pid"
      else
         isrunning="yes"

         # make sure the process is killed. keep trying.
         while [ -n "$isrunning" ]; do
            echo "Established session for user $euser is gone. killing pid $pid.."
            kill $pid
            sleep 1
            isrunning=`ps -ef | grep $pid | grep -v grep`
            test -z "$isrunning" && echo "$pid killed OK"
         done
      fi
   done
done

相关内容