TCP 控制 Socket Server

概觀

控制 socket server 是 gevent 為基礎的 TCP listener,將收到的 LoadDensity 動作 JSON 透過網路執行。硬化版協定加入 length-prefix framing、選用 TLS,以及共享密鑰 token;舊版未驗證模式仍保留以維持相容。

模式

模式

註記

legacy

單次 recv(8192)、純 JSON、無驗證。預設模式以維持舊客戶端(如 PyBreeze)相容。

framed

4-byte big-endian 長度前綴 + JSON body。對 partial read 與超大 payload 較安全(1 MiB 上限)。

framed + TLS

``ssl.create_default_context``(TLS 1.2+)包裝連線,需 cert/key 檔案。

驗證

傳入 token=``(或設定 ``LOAD_DENSITY_SOCKET_TOKEN)即可要求共享密鑰。一旦設定:

  • quit_server 沒有正確 token 將被拒絕。

  • 所有指令 payload 必須使用 envelope {"token": "...", "command": [...action JSON...]},可以 "op": "quit" 表示停機。

Token 以 hmac.compare_digest 比對,避免 timing oracle。

啟動 server

Python:

from je_load_density import start_load_density_socket_server

start_load_density_socket_server(
    host="0.0.0.0",
    port=9940,
    framed=True,
    token="ROTATE_ME",
    certfile="/etc/loaddensity/server.crt",
    keyfile="/etc/loaddensity/server.key",
)

CLI:

python -m je_load_density serve \
    --host 0.0.0.0 --port 9940 --framed \
    --token "$LOAD_DENSITY_SOCKET_TOKEN"

傳送指令(framed 模式)

import json, socket, struct

payload = json.dumps({
    "token": "ROTATE_ME",
    "command": {"load_density": [["LD_summary", {}]]}
}).encode("utf-8")

sock = socket.create_connection(("127.0.0.1", 9940))
sock.sendall(struct.pack("!I", len(payload)) + payload)
while True:
    header = sock.recv(4)
    if not header:
        break
    (length,) = struct.unpack("!I", header)
    chunk = sock.recv(length)
    if chunk == b"Return_Data_Over_JE\n":
        break
    print(chunk.decode("utf-8"))
sock.close()

關閉

  • Legacy 模式:傳送字面字串 quit_server

  • Framed 模式(含 token):傳送 {"token": "...", "op": "quit"}

Server 列印 Server shutdown complete 後結束。

注意事項

  • 啟動時會呼叫 gevent.monkey.patch_all(),整合時請留意。

  • token 可由環境變數 LOAD_DENSITY_SOCKET_TOKEN 讀取,避免將密鑰寫進指令參數。