作者[系統]
看板PttCurrent
標題[開發資訊] 連線保持與防閒置 (Keep-Alive) 實作建議
時間Wed Sep 23 23:29:53 CST 2026
PTT 終端機連線與防閒置 (Keep-Alive / Anti-Idle) 實作建議
為提升連線穩定度並避免干擾新版介面操作,我們建議所有實作「防閒置
(Anti-Idle)」或「連線保持 (Keep-Alive)」的 App / Web Client
開發者,一律改用標準 Telnet TIMING-MARK (RFC 860) 協定指令。
支援狀態: PTT1 / PTT2 全站已原生支援 (無須等待伺服器改版)
適用於 WebSocket (wss://ws.ptt.cc/bbs) 連線
影響範圍: 所有具備定時防閒置 (Anti-Idle / Keep-Alive) 或
斷線偵測機制的 BBS Client / App / 瀏覽器擴充套件。
說明:
PTT 站方目前設定為「不會」因為使用者閒置而主動斷線(除非系統負載過高)
所以理論上不需要特別設置防閒置功能,但由於現代網頁與 App長期保持連線的
狀況比較少見,許多網路設備(防火牆、路由器、...)都有長期無傳輸就切斷
連線的機制,如果是行動網路甚至可能數分鐘就切斷。
因此,我們理解使用者會有防閒置的需求以配合實際網路。一般為了防止
使用者久未操作遭伺服器或網路設備斷線,會定時在背景自動發送封包。
然而傳統常見的幾種做法存在明顯副作用或網路層缺陷:
1. 傳統防閒置做法的問題
(a) 定時發送一般按鍵或控制字元 (應全面停用)
- 常見舊做法:送出 NUL (0x00)、Ctrl-L (0x0C)、Space、Backspace、
Esc、或方向鍵組合 (如 \x1bOA\x1bOB) 等。
- 問題:這些位元組會進入 BBS 的鍵盤輸入緩衝區 (vkey),被當作真
實按鍵處理。在各列表、單行輸入提示 (getdata)、推文、編輯器或
新版 [i] 看板資訊等畫面中,極易造成誤觸功能、關閉提示視窗、打
斷輸入狀態或引發畫面無故重繪,例如「畫面會定期抖一下」。
(b) 定時發送 Telnet IAC NOP (0xFF 0xF1) 或 IAC AYT (0xFF 0xF6)
- IAC NOP (0xFF 0xF1) 屬於「單向靜默指令」:
伺服器收到後僅會在底層將其吸收忽略,【不會回傳任何封包】。當
使用者處於行動網路、NAT 分享器、防火牆或 WebSocket Proxy 後方
時,由於缺乏「Server -> Client」的雙向回應流量,中間網路設備
仍可能判定該連線已僵死 (Stalled / Half-open) 而切斷連線,且
Client 端也無法藉此得知連線是否已經實質斷開。
- IAC AYT (0xFF 0xF6, Are You There) 會污染畫面:
伺服器收到 AYT 會直接回傳明文字串 "I'm still alive.\r\n" 至畫
面串流中,導致終端機畫面出現雜訊與排版錯亂。
2. 推薦標準做法:使用 Telnet IAC DO TIMING-MARK (RFC 860)
我們建議所有 Client 統一改送 Telnet TIMING-MARK (Option 6) 請求:
(a) 完全不干擾 BBS 狀態與畫面:
該序列在伺服器端輸入管線的 Telnet 過濾層 (telnet_filter_process)
就會被完整攔截並消化,【不會進入vkey輸入緩衝區】,不會對使用者
目前的畫面、游標、選單或輸入狀態產生任何影響。
(b) 具備雙向收發 (Ping / Pong) 效果:
伺服器收到 IAC DO TIMING-MARK 後,會立即在協定層主動回傳 3 個
bytes 的協商回應。這能確保 Client 與 Server 雙向皆有實際封包流
動,有效刷新中間路由器 / 防火牆 / WebSocket 的連線逾時計時器,
同時讓 Client 可藉由是否收到回應來偵測半開斷線 (Dead Peer)。
3. 實際傳送與接收的位元組 (Bytes) 規格
(a) Client 發送端 (Request: 固定 3 Bytes):
觸發防閒置時,請直接向底層 Socket / WebSocket 送出以下 3 個原始
位元組 (Raw Bytes):
* 協定語意:IAC + DO + TIMING-MARK
* 十六進位:0xFF 0xFD 0x06
* 十進位值:255, 253, 6
* 程式範例:new Uint8Array([0xff, 0xfd, 0x06]) (JavaScript)
b"\xff\xfd\x06" (Python / C)
* 各 Byte 定義:
- Byte 0: 0xFF (255): IAC (Interpret As Command)
- Byte 1: 0xFD (253): DO (請求對方執行選項)
- Byte 2: 0x06 ( 6): TIMING-MARK (RFC 860 Option 6)
【注意】發送此序列時,請走底層原始發送路徑 (sendRaw),切勿經過
一般文字輸入的 IAC 跳脫函式 (不可將 0xFF 變成 0xFF 0xFF)。
(b) Server 回應端 (Response: 固定 3 Bytes):
伺服器收到上述 3 Bytes 後,會立即回傳以下 3 Bytes 協商回應:
* PTT (pttbbs) 回傳:IAC + WONT + TIMING-MARK
- 十六進位:0xFF 0xFC 0x06 (十進位:255, 252, 6)
【注意】傳回 WONT 而非 WILL 是故意的,因為 WILL 會要進入
下一步協商而不能再一直問,所以一般使用 TIMING-MARK
作的作法就是傳 WONT 然後可以重複讓 cilent 傳 DO。
* 給第三方程式開發者的建議
1. 請將程式內的防閒置 (Anti-Idle) 發送內容改為上述的 3 Bytes 原始序列:
`0xFF 0xFD 0x06` (IAC DO TIMING-MARK),建議發送間隔設為 180~300 秒,
且當使用者有正常按鍵輸入時即可重置計時器。
2. 請檢查您的 Telnet 接收端狀態機 (Inbound Filter):當收到伺服器回傳的
`0xFF 0xFC 0x06` (IAC WONT 0x06) 或 `0xFF 0xFB 0x06` (IAC WILL 0x06)
時,請直接【忽略】,勿將其當作一般字元繪製到畫面上。
3. 當收到伺服器的 `IAC WILL 0x06` (或 `WONT 0x06`) 回應時,Client 請勿
再自動回覆 `IAC DONT 0x06` (`0xFF 0xFE 0x06`),以免產生多餘的往返封包。
4. 請全面移除送出 `0x00` (NUL)、`^L`、空白鍵或方向鍵等模擬按鍵的舊式防
閒置實作,以避免干擾使用者操作及畫面狀態判讀。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
※ 文章網址: https://webptt.com/m.aspx?n=bbs/PttCurrent/M.1790178013.A.9FB.html