如何找到斷開連線的 xrdp 會話?

如何找到斷開連線的 xrdp 會話?

我這裡有一個 Xubuntu 14.04 伺服器,它運行 xrdp 以讓幾個用戶連接到它。
現在有一個問題:從 Windows 瘦客戶端透過 RDP 存取該伺服器的使用者經常使用「X」來關閉 RDP 會話(因此斷開連線但不登出)。

我知道 sesman.ini 中有一些選項可以處理這種行為,但正如線上說明頁所述,這些選項目前被忽略(並且已經存在多年)。
可以解決我的問題的選項是:
KillDisconnected
DisconnectedTimeLimit
IdleTimeLimit

現在我需要破解一些處理斷開連接的會話的東西。我的第一個想法是殺死所有斷開連接的遠端用戶 - 但我不知道如何獲取哪些會話已斷開連接的資訊。

那麼...我要如何找到斷開連線的會話?
或者:是否已經有任何首選方法來處理斷開連接的會話?

答案1

這是獲取斷開連線的 xrdp 會話清單的方法。它依賴於這樣一個事實:XRDP在正常的 X 會話管理器使用中,伺服器是唯一與伺服器建立 TCP 連線的用戶端。XVNCX Window 系統顯示伺服器。當 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 顯示伺服器進程上沒有 ESTABLISHED 連線。因此,任何僅偵聽的 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按編號為 5900 - 5999 的 TCP 連接埠進行過濾,這些連接埠用於 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

謝謝你的lsof-fu!偵測「死」Xvnc會話一直是Xrdp.我已將 O. Jones 的程式碼合併到一個 shell 腳本中,該腳本可以在啟動時加載並從螢幕運行,以清理Xvnc當用戶關閉 RDP 視窗或由於某種原因連接斷開時留下的死進程。我從來沒有找到一種方法來Xrdp處理這個問題,所以這段lsof程式碼是完美的。

#!/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

相關內容