# SOCKET 子系統 — 所有 EXE / BAT 用途・配合・執行順序（2026-06-12 更新版）

> 取代 2026-06-10 版。新增：**RDP Takeover（跨帳號接管）子系統**、**Cloudflare DDNS**、
> **三層更新器（uploader / server_updater / stk_updater）**、**ffmpeg7 32/64 並存**、
> 以及多處功能修正（pusher 輸入注入、WebScreen 切換重連、多 host relay）。
> 文末新增「**彼此如何配合・先後執行順序・流程圖・分時圖**」。

---

## 0. 四個角色 + 一條主資料流

| 角色 | 機器 | 常駐程式 |
|---|---|---|
| **客戶站台**（被遠端） | 客戶機（C:\STK\Sxxx） | StkAgent + pusher +（SYSTEM）session_pusher |
| **SERVER**（中央/橋接） | Server | Relay + StkWebScreen + cloudflared + cf_ddns |
| **操作端 PC** | 操作員 PC | StkCommander |
| **手機/平板/瀏覽器** | 任意 | 只開網頁，不裝東西 |

**主資料流（看畫面）**：
```
客戶站台 pusher ──H.264──▶ SERVER Relay(9530) ──轉發──▶ StkWebScreen 橋接(8080) ──mpegts/HLS──▶ 瀏覽器
                                                  └──▶ StkCommander(mpv)
```
**操控流（反向）**：瀏覽器/Commander ──input──▶ Relay ──▶ Agent ──▶ 桌面（SendInput / RDP 跨 session 注入）

---

## 一、Relay（中繼伺服器）— 跑在 SERVER

> 部署：`C:\socket\relay`；對外埠 **9530**（raw TCP，H.264 與控制複用同埠）。

| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **relay_server.exe** | EXE 常駐 | 中繼核心：9530 收所有 agent 推流 + commander/橋接控制，依 KMSN:STATION 轉發給 viewer；A/B 雙槽 | 24h 常駐 |
| **install_relay.bat** | BAT | 一鍵安裝：A/B + 防火牆 + 排程（STK_Relay_Server 開機自啟 / STK_Relay_Watchdog 每5分自癒）+ 立即啟動 | 首次裝一次 |
| **watchdog_relay.bat** | BAT | 自癒核心：挑最新 A/B、確保**單一實例**且 9530 在聽，否則 kill 全部→等乾淨→啟動一個（防雙開搶埠） | 排程每5分（不手動） |
| **update_relay.bat** | BAT | 升級：新 exe 寫進沒鎖的 A/B 槽，watchdog 自動切最新 | 升級 relay 時 |
| **start_relay.bat / run_relay.bat** | BAT | 手動前景啟動（測試用） | 臨時手動開 |
| **uninstall_relay.bat** | BAT | 移除排程 + 防火牆 | 卸載 |
| **install_service.bat** | BAT | ⚠️已淘汰：導向 install_relay.bat | 不要用 |
| **★ cf_ddns.exe**（cf_ddns.py） | EXE | 🆕 **Cloudflare DDNS**：抓本機公網 IP → 更新 `relay.asiaware-stk.com` A 紀錄（灰雲 proxied=False）。解決中華電信固定 IP 會變的問題 | 排程 STK_CF_DDNS 每5分 |
| **★ cf_ddns.ini** | INI | 🆕 token / zone / record / ttl；列入 server_updater **NO_OVERWRITE**（更新不覆蓋，token 只放 Server 本機） | — |
| **★ install_cf_ddns.bat** | BAT | 🆕 一鍵裝 DDNS：註冊排程 **STK_CF_DDNS**（/sc minute /mo 5 /ru SYSTEM）+ 立即跑一次 | 首次裝一次 |

---

## 二、StkWebScreen（網頁橋接）— 跑在 SERVER

> 部署：`C:\socket\StkWebScreen`；對內埠 **8080**，對外經 Cloudflare Tunnel。
> ⚠️ 橋接與 Relay 是**分開的程序**：重啟 Relay 時橋接不關，瀏覽器才看得到「維護中」並自動續播。

| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **Stk_WebScreen.exe** | EXE 常駐 | 網頁橋接：連 Relay 當 viewer，對瀏覽器提供 **操控頁 /m**（mpegts+WS，低延遲）與 **純看頁 /h**（HLS，iPhone）；含登入、畫質、剪貼簿、維護提示、**🆕 RDP 帳號選擇器** | 24h 常駐 |
| **cloudflared.exe** | EXE 常駐 | Cloudflare Tunnel：把內網 8080 用 HTTPS 網域對外（免開路由器埠） | 對外服務 |
| **ffmpeg7.exe** | EXE | 64-bit ffmpeg：橋接把 Relay 串流 `-c copy` 切成 HLS 給 iPhone | 純看頁 /h |
| **★ watchdog_webscreen.bat** | BAT | 🆕 自癒：保橋接(:8080)+tunnel 活著；偵測 `*.new`（server_updater 對鎖住的 exe 寫的新版）→ 停→swap→重啟新版 | SYSTEM 排程開機+每5分 |
| **★ install_webscreen.bat** | BAT | 🆕 一鍵裝橋接：自我提權、放 C:\ 或 UNC（**不可放 W: 對應磁碟**，SYSTEM 看不到）+ 註冊 SYSTEM 排程 | 首次裝一次 |
| **auto_start.bat** | BAT | 開機自啟（橋接+tunnel），無排程環境用 | 替代方案 |
| **start_webscreen.bat / start_external.bat** | BAT | 手動啟動（不含/含 tunnel） | 測試 |
| **allow_8080.bat** | BAT | 防火牆放行 8080 | 首次/連不進 |
| **setup_named_tunnel.bat / install_named_tunnel_service.bat** | BAT | 設定具名 tunnel（綁網域）/ 裝成服務 | 首次設網域 |

---

## 三、StkAgent（站台代理）— 跑在「客戶站台」

> 部署：客戶機本機（例 `C:\STK\S001`）；**Agent/pusher 必須在使用者登入的桌面 session 跑**（要抓桌面，不能 Service/Session 0）。
> 🆕 **session_pusher 例外**：它本身不抓畫面、只負責「把 pusher 丟進指定 session」，需要 SYSTEM 權限 → 反而**必須**用 SYSTEM 排程。

### EXE
| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **Stk_Agent_A/B.exe** | EXE 常駐 | 站台代理：連 Relay 註冊、收 START_STREAM 啟 pusher、收 INPUT 操控桌面、心跳、檔案/剪貼簿；A/B 雙槽熱抽換。🆕 RDP takeover、🆕 多 host relay（RELAY_HOST,ALT,ALT2 逗號串逐一試） | 登入後常駐（使用者 session） |
| **pusher.exe**（agent_pusher.py） | EXE | 推流：抓桌面→ffmpeg 編 H.264→推 Relay。🆕 **加 UDP 9542 輸入監聽**（RDP 跨 session 注入）、🆕 **fps 濾鏡**（畫面靜止不變黑）、🆕 依 OS 位元選 ffmpeg7_32/64 | 由 agent 或 session_pusher 啟動 |
| **ffmpeg.exe** | EXE | 32-bit ffmpeg 4.2.2：pusher 用 **gdigrab** 擷取桌面（通用） | gdigrab |
| **★ ffmpeg7_64.exe / ffmpeg7_32.exe** | EXE | 🆕 **64/32 並存**（取代單一 ffmpeg7）：pusher 依**作業系統位元**自動挑；32-bit FFmpeg 8.x（defisym build）也有 ddagrab+qsv，讓 32 位元機也能用 GPU | ddagrab/GPU |

### 🆕 RDP Takeover 子系統（跨帳號接管的核心）
| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **session_pusher.exe**（tools/session_pusher.py） | EXE 常駐 | 🆕 **SYSTEM 權限**：① 每秒用 WTSEnumerateSessions 枚舉**所有帳號 session** 寫 `sessions.json`（一般使用者的 Agent 看不到別帳號，要靠這個）；② 讀 `session_req.json`，用 WTSQueryUserToken + **CreateProcessAsUser** 把 pusher **丟進指定 sid 的桌面**（換帳號接管） | SYSTEM 排程 STK_RDP_Watch 常駐 |
| **rdp_watch.bat** | BAT | 🆕 **穩定外殼（永不改版）**：被排程拉起，迴圈跑 session_pusher --watch；偵測 `session_pusher.exe.new`→taskkill+swap+重啟（**自動換版核心**，避免「執行中鎖住自己換不了版」） | 排程每次啟動 |
| **install_rdp_follow.bat** | BAT | 🆕 一鍵裝 RDP-follow：先 end 排程+kill+刪舊 .new，再複製 session_pusher/rdp_watch/pusher/ffmpeg/**OS對應 ffmpeg7**，註冊 SYSTEM 排程 **STK_RDP_Watch**。已整合進 install_agent(.bat/_silent) | 隨 agent 安裝 |

### 安裝 / 自啟 / 維運 BAT
| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **install_agent.bat** | BAT | 首次安裝/更新（互動）：複製 A/B+pusher+ffmpeg、輸入 STATION/KMSN 寫 ini、防火牆、設使用者 session 自啟、🆕 call install_rdp_follow、立即啟動 | 首次裝一次 |
| **install_agent_silent.bat** | BAT | 無互動安裝/更新：讀現有 ini，可遠端觸發；🆕 含 install_rdp_follow /q | 遠端批次/自動更新 |
| **watchdog_user.bat** | BAT | 使用者版自癒：挑最新 A/B、單一實例、heartbeat、否則 kill→等乾淨→啟一個 | agent_autostart.vbs 每60秒 |
| **agent_autostart.vbs** | VBS | 登入自啟迴圈：每60秒隱藏視窗呼叫 watchdog_user.bat（自啟+自癒，在桌面 session） | 啟動資料夾捷徑 |
| **setup_autostart_user.bat** | BAT | 把舊安裝轉成使用者 session 自啟（刪 SYSTEM 排程黑畫面、建啟動捷徑） | 修舊機自啟 |
| **_restart_agent.bat** | BAT | 重啟 agent（A/B 切換部署） | 部署新版後 |
| **uninstall_agent.bat / unblock_all.bat** | BAT | 卸載 / 解除 exe 封鎖屬性 | 卸載 / 被 SmartScreen 擋 |
| **watchdog_agent.bat/.vbs** | — | ⚠️已淘汰：舊 SYSTEM 排程（Session 0 黑畫面），由 watchdog_user 取代 | 不要用 |

---

## 四、StkCommander（桌面控制台）— 操作端 PC

| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **Stk_Commander.exe** | EXE | 桌面控制台：列上線站台、遠端桌面（mpv 播 Relay 串流）、檔案傳輸（保留日期）、截圖、訊息、錯誤紅點、切站 | 操作員手動 |
| **mpv.exe** | EXE | 影片播放器：播 Relay 遠端桌面 H.264 | Commander 開遠端桌面 |

---

## 五、ErrorMonitor（錯誤監看）

| 檔案 | 類型 | 用途 | 時機 |
|---|---|---|---|
| **ftp_error_monitor.exe** | EXE 常駐 | 每30秒掃 FTP 錯誤回報目錄，有新錯誤推 Telegram（含截圖） | 啟動資料夾常駐 |

---

## 六、🆕 三層更新器（開發機 / SERVER / 客戶站台各一）

> 出版流程：開發機 **uploader** 打包上傳 FTP →（SERVER）**server_updater** 抓 relay/webscreen →（客戶站台）**stk_updater** 抓 agent。

| 檔案 | 跑在 | 用途 |
|---|---|---|
| **stk_uploader.exe**（stk_uploader.py） | 開發機 | 🆕 蒐集各元件最新檔（含 cf_ddns、session_pusher、ffmpeg7_32/64、rdp_watch、install_rdp_follow）→ 分群組打包上傳 FTP |
| **server_updater.exe**（server_updater.py） | **SERVER** | 🆕 從 FTP 抓 SOCKET/relay → C:\socket\relay（relay A/B、cf_ddns）、SOCKET/webscreen → C:\socket\StkWebScreen（exe 鎖住寫 .new）；**NO_OVERWRITE**＝relay_agent.ini / stk_webscreen.ini / **cf_ddns.ini** 不覆蓋 |
| **stk_updater.exe**（stk_updater.py） | 客戶站台 | 從 FTP 抓 agent 檔派送到各站（含 session_pusher / install_rdp_follow / rdp_watch / ffmpeg7_32/64） |

---

## 七、建置工具（開發機）

| 檔案 | 用途 |
|---|---|
| **_build_all_socket.bat** | 一鍵編譯四元件，build 後複製回來源目錄（避免上傳到舊 exe） |
| **StkAgent/tools/_compile_screenshot.bat** | 重編 screenshot.c 的 .obj（截圖/剪貼簿 C 碼） |

---

## 八、彼此如何配合・先後執行順序

### 8-1 開機自啟順序

**SERVER（一直開機）**
```
開機
 ├─ 排程 STK_Relay_Server ─▶ relay_server.exe（A/B 最新槽）
 ├─ 排程 STK_Relay_Watchdog（每5分）─▶ watchdog_relay.bat（單一實例自癒）
 ├─ 排程 STK_WebScreen_Watchdog（開機+每5分）─▶ watchdog_webscreen.bat ─▶ Stk_WebScreen.exe + cloudflared.exe
 └─ 排程 STK_CF_DDNS（每5分）─▶ cf_ddns.exe（追公網 IP）
```

**客戶站台（使用者登入後）**
```
登入
 ├─ 啟動資料夾捷徑 ─▶ agent_autostart.vbs（每60秒）─▶ watchdog_user.bat ─▶ Stk_Agent_A/B.exe（使用者 session，可抓桌面）
 └─ 排程 STK_RDP_Watch（SYSTEM）─▶ rdp_watch.bat ─▶ session_pusher.exe --watch
        └─ 每秒寫 sessions.json；待命接 session_req.json
```
> ⚠️ 為什麼分兩路：Agent 要抓桌面 → 必須使用者 session；session_pusher 要把 pusher 丟進**別的帳號 session** → 必須 SYSTEM 權限。兩者權限相反，故拆開。

### 8-2 一次「WEB 看畫面 + 操控」完整時序
```
① 瀏覽器開網域 ─cloudflared─▶ Stk_WebScreen /m（登入頁→操控頁）
② 選站台 S001 ─▶ WebScreen start_stream ─▶ send_cmd START_STREAM ─Relay─▶ Agent
③ Agent 寫 session_req.json{action:start, sid:N} ─▶ session_pusher 讀到
④ session_pusher: taskkill 舊 pusher ─CreateProcessAsUser─▶ 把 pusher 丟進 sid=N 的桌面
⑤ pusher: ffmpeg 抓桌面 ─H.264─▶ 推 Relay 9530
⑥ Relay 依 KMSN:STATION 轉發 ─▶ WebScreen viewer ─mpegts─▶ 瀏覽器看到畫面
⑦ 操控：瀏覽器 WS input ─▶ WebScreen ─Relay─▶ Agent
        ├─ RDP active? ─▶ RdpForwardInput ─UDP 127.0.0.1:9542─▶ pusher 內建注入器 ─SendInput─▶ 目標 session 桌面
        └─ 否 ─▶ AGENT_SENDINPUT 直接注入本 session
```

### 8-3 🆕 RDP Takeover 換帳號（本次修正的重點）
```
WEB 點「🖥 RDP」─▶ /rdpsessions ─▶ Agent 回 RdpListSessions()（讀 sessions.json）─▶ 列出 3 個帳號
使用者點某帳號 sid ─▶ /rdpsid set_rdp_sid ─▶ 重發 START_STREAM(rdpsid=sid)
   ─▶ Agent 重寫 session_req(sid) ─▶ session_pusher 殺舊 pusher + CreateProcessAsUser 新 sid ─▶ 開「全新 H.264 流」
   ─▶ ★ 瀏覽器 reconnectStream() 重連到新流（否則卡舊流→凍住不黑，要返回選站台才生效）
   ─▶ 看到該帳號桌面，可操控
```

### 8-4 自動換版（四路，各自獨立）
| 對象 | 機制 | 切換者 |
|---|---|---|
| Stk_Agent | A/B 雙槽：updater 寫沒鎖的槽 | _restart_agent / watchdog_user 切最新 |
| relay_server | A/B 雙槽：server_updater 寫沒鎖的槽 | watchdog_relay 切最新 |
| Stk_WebScreen | exe 鎖住→server_updater 寫 `.new` | watchdog_webscreen swap |
| session_pusher | 鎖住→寫 `.new` | **rdp_watch.bat** swap（穩定外殼） |

### 8-5 🆕 Cloudflare DDNS（IP 變動自癒）
```
中華電信機房重開 → 固定 IP 變
 └─ cf_ddns（每5分）抓新公網 IP ─Cloudflare API─▶ 更新 relay.asiaware-stk.com（灰雲）
        └─ 客戶端 RELAY_HOST_ALT2=relay.asiaware-stk.com 解析到新 IP
               └─ Agent RelayArg() 把 RELAY_HOST,ALT,ALT2 逗號串逐一嘗試 → 任一條通就連上 Relay
```

---

## 速查：哪台跑哪些常駐程式

| 機器 | 常駐 EXE | 自啟方式 |
|---|---|---|
| **SERVER** | relay_server / Stk_WebScreen / cloudflared / **cf_ddns** | 排程（Relay/WebScreen Watchdog、STK_CF_DDNS）|
| **客戶站台** | Stk_Agent_A（+START_STREAM 時 pusher/ffmpeg）/ **session_pusher** | Agent→啟動資料夾 vbs；session_pusher→SYSTEM 排程 STK_RDP_Watch |
| **操作端 PC** | Stk_Commander（操作時開） | 手動/捷徑 |
| **監看機** | ftp_error_monitor | 啟動資料夾 |

---

## 重要觀念備忘

1. **Agent / pusher 抓桌面 → 只能使用者 session 自啟**（啟動資料夾），不能 Service/SYSTEM（Session 0=黑畫面）。
2. **session_pusher 相反：要把 pusher 丟進別帳號 session → 必須 SYSTEM**；它本身不抓畫面所以無桌面需求。
3. **relay / 橋接 / cf_ddns 無桌面 → 可放 SYSTEM 排程 / Service**。
4. **ffmpeg7 32/64 並存**：pusher 依 OS 位元自動挑；別再以為「32 位元站台不能用 GPU」。
5. **換 RDP 帳號／切回一般→瀏覽器一定要 reconnectStream()**，否則卡舊流凍住。
6. **cf_ddns.ini 的 token 只放 SERVER 本機**（NO_OVERWRITE），dev 來源那份 token 留空，避免上 FTP。
7. **重啟 relay 時不要關橋接**：橋接活著瀏覽器才顯示「🔧 中繼站維護中」並自動續播。
</content>
