Python 多執行緒 TCP Client 完整實作教學(自動重連 + 封包記錄)

更新 發佈閱讀 10 分鐘

本篇教學將帶你實作一個:

  • ✅ 多執行緒 TCP Client
  • ✅ 支援自動斷線重連
  • ✅ 非阻塞收發機制
  • ✅ Queue 非同步發送
  • ✅ JSON 封包格式
  • ✅ 自動依照日期分類儲存封包 Log
  • ✅ Windows Port 被占用處理

這是一個適合工業設備通訊(例如 AVI 檢測系統)或客製化 TCP 協議應用的完整架構範例。


一、整體架構設計

我們的程式包含三個主要類別:

Request        → 封包物件
LogHandler → 訊息回呼機制
TCPClient → 核心 TCP 通訊引擎

架構流程如下:

外部程式

SendData()

tx_queue

TCP Thread

sendall()

Server

Server 回傳

recv()

rx_queue

外部程式處理

二、Request 封包設計

class Request:
def __init__(self, cmd, data):
self.Cmd = cmd
self.Data = data

def to_json(self):
return json.dumps({"Cmd": self.Cmd, "Data": self.Data}, ensure_ascii=False)

設計重點

  • 將封包格式統一為:
{
"Cmd": "PUT_AVIRESULT_REQ",
"Data": {
"PN": "ABC123",
"SN": "0001"
}
}
  • ensure_ascii=False
    → 支援中文

這樣可以確保整個系統的封包格式一致。


三、LogHandler 訊息回呼系統

class LogHandler:
def __init__(self):
self.callbacks = {}

def register(self, name, callback):
self.callbacks[name] = callback

def emit(self, msg):
for callback in self.callbacks.values():
callback(msg)

為什麼需要它?

讓 TCPClient 不直接依賴 UI 或 print。

例如在 PyQt 中可以這樣註冊:

client.logHandlers.register("ui", lambda msg: print(msg))

這樣 TCPClient 就變成:

可嵌入 GUI、Console、Server 程式的通用元件

這是一種 解耦設計(Decoupling Design)


四、TCPClient 核心解析


1️⃣ 初始化

class TCPClient:
def __init__(self):
self.remote_addr = ("127.0.0.1", 9999)
self.local_addr = None
self.sock = None
self._isconnected = False
self._running = False
self.tx_queue = queue.Queue()
self.rx_queue = queue.Queue()
self.logHandlers = LogHandler()
self.log_root = "C:/AVI_Packet"

重點

變數功能tx_queue發送佇列rx_queue接收佇列_running執行緒是否運行_isconnected是否已連線


五、多執行緒設計

def start(self):
if self._running: return
self._running = True
self.thread = threading.Thread(target=self._tcp_thread, daemon=True)
self.thread.start()

使用:

daemon=True

代表主程式結束時,TCP thread 會自動關閉。


六、自動重連機制(核心重點)

if not self._isconnected:

重連流程:

  1. 關閉舊 socket
  2. 建立新 socket
  3. 設定 SO_REUSEADDR
  4. 綁定 local port
  5. 設定 timeout
  6. connect
  7. 切回 non-blocking

1️⃣ 為什麼要 shutdown?

self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()

確保:

  • 舊 socket 立即釋放
  • 不會殘留 TIME_WAIT

2️⃣ Windows Port 10048 問題處理

self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

如果 Port 被佔用:

self.sock.bind((self.local_addr[0], 0))

改用系統自動分配 Port。

這是實務上非常重要的穩定性優化。


3️⃣ 為什麼 connect 之後要設為 non-blocking?

self.sock.setblocking(False)

如果不這樣:

recv() 會卡死

七、收發邏輯解析


1️⃣ 發送資料(優先處理)

if not self.tx_queue.empty():

轉換 JSON:

if isinstance(obj, Request):
json_str = obj.to_json()

然後發送:

self.sock.sendall((json_str.strip() + "\r\n").encode('utf-8'))

為什麼加 \r\n

因為我們用它當作封包分隔符。


八、接收資料設計

raw_rx = self.sock.recv(4096)

如果:

if not raw_rx:

代表:

Server 已關閉連線

然後拆分:

msgs = raw_rx.decode('utf-8').split("\r\n")

每筆封包丟入:

self.rx_queue.put(m)

九、斷線判斷機制

捕捉:

except (socket.error, ConnectionResetError)

任何錯誤都視為:

斷線

然後:

_isconnected = False

下一輪自動重連。


十、封包自動存檔系統

C:/AVI_Packet/
2026/
0226/
ABC_SN_timestamp.json

建立路徑:

folder_path = os.path.join(self.log_root,
now.strftime("%Y"),
now.strftime("%m%d"))

根據 Cmd 命名檔案:

Cmd檔名REGISTER_REQREGISTER_時間.jsonPUT_AVIRESULT_REQPN_SN_時間.json

這對於:

  • 產線追蹤
  • 問題追查
  • 資料留存

非常實用。


十一、智慧休眠設計

if not active_work:
time.sleep(0.01)
time.sleep(0.005)

目的:

  • 降低 CPU 使用率
  • 不影響即時性

這比無限 while True 空轉好很多。


十二、完整使用範例

client = TCPClient()

client.setRemote("127.0.0.1", 9999)

client.logHandlers.register("console", print)

client.start()

req = Request("PUT_AVIRESULT_REQ", {
"PN": "ABC123",
"SN": "0001"
})

client.SendData(req)

十三、這個架構的優點

✔ 穩定自動重連


✔ 不會卡住 UI ✔ 支援 GUI / Console ✔ 可處理高頻封包 ✔ 可追蹤歷史封包 ✔ Windows 相容優化



十四、可進一步優化方向

  1. 增加心跳機制
  2. 增加最大重試次數
  3. 加入 SSL/TLS
  4. 封包加上序號
  5. 使用 asyncio 重寫(高併發版本)

十五、總結

這是一個:

工業等級 TCP Client 架構

它解決了:

  • Port 被占用
  • 斷線殘留
  • 阻塞卡死
  • 重連不穩定
  • 封包無紀錄

等常見問題。

留言
avatar-img
螃蟹_crab的沙龍
166會員
322內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。 興趣是攝影,踏青,探索未知領域。 人生就是不斷的挑戰及自我認清,希望老了躺在床上不會後悔自己什麼都沒做。
螃蟹_crab的沙龍的其他內容
2024/08/11
避免 thread 競速(Race Condition)是多執行緒編程中常見的挑戰之一。 Race Condition 發生在多個執行緒同時訪問和修改共享資源時,因為執行緒之間的執行順序無法預測,可能會導致數據的不一致性或意外行為。 本文主要介紹如何使用Lock來避免此狀況出現。 首先先看沒
Thumbnail
2024/08/11
避免 thread 競速(Race Condition)是多執行緒編程中常見的挑戰之一。 Race Condition 發生在多個執行緒同時訪問和修改共享資源時,因為執行緒之間的執行順序無法預測,可能會導致數據的不一致性或意外行為。 本文主要介紹如何使用Lock來避免此狀況出現。 首先先看沒
Thumbnail
2024/03/22
在Python中,queue是一個非常有用的模块。 它提供了多種佇列(queue)實現,用於在多線程環境中安全地交換信息或者數據。 佇列(queue)是一種先進先出(FIFO)的數據結構,允許在佇列的一端插入元素,另一端取出元素。(FIFO 是First In, First Out 的縮寫)
Thumbnail
2024/03/22
在Python中,queue是一個非常有用的模块。 它提供了多種佇列(queue)實現,用於在多線程環境中安全地交換信息或者數據。 佇列(queue)是一種先進先出(FIFO)的數據結構,允許在佇列的一端插入元素,另一端取出元素。(FIFO 是First In, First Out 的縮寫)
Thumbnail
2024/03/21
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
2024/03/21
當你需要在 Python 中執行多個任務,但又不希望它們相互阻塞時,可以使用 threading 模組。 threading 模組允許你在單個程序中創建多個執行緒,這些執行緒可以同時運行,從而實現並行執行多個任務的效果。
Thumbnail
看更多
你可能也想看
Thumbnail
IDE 升級後出現了一樣的錯誤,手上程式碼沒有 pylint black-format 檢查上不了 gitlab,我又點開了那個很小很小的 x 符號,裡面 logs 提示的解決方式是升級..
Thumbnail
IDE 升級後出現了一樣的錯誤,手上程式碼沒有 pylint black-format 檢查上不了 gitlab,我又點開了那個很小很小的 x 符號,裡面 logs 提示的解決方式是升級..
Thumbnail
題目會給我們一個山形的輸入陣列,和目標值target,要求我們找出目標值所在的陣列索引。如果出現兩次,返回比較小的那一個,也就是比較靠左的那個索引值。 山形的意思就是說,從最左側到山頂最大值都是遞增,從山頂最大值到右側都是遞減。
Thumbnail
題目會給我們一個山形的輸入陣列,和目標值target,要求我們找出目標值所在的陣列索引。如果出現兩次,返回比較小的那一個,也就是比較靠左的那個索引值。 山形的意思就是說,從最左側到山頂最大值都是遞增,從山頂最大值到右側都是遞減。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
一、為什麼需要 3x3 矩陣?避開單一指標的盲點 在海量的全球股市數據中,投資人最常犯的錯誤是「只看加權指數」或「只看單一均線」。然而,指數的漲跌往往被權值股(如美股的 Mag 7 或台股的台積電)所掩蓋。 為了看清市場整體的「健康程度」,我開發了這套 3x3 分佈矩陣分析引擎: 橫向維度(時
Thumbnail
一、為什麼需要 3x3 矩陣?避開單一指標的盲點 在海量的全球股市數據中,投資人最常犯的錯誤是「只看加權指數」或「只看單一均線」。然而,指數的漲跌往往被權值股(如美股的 Mag 7 或台股的台積電)所掩蓋。 為了看清市場整體的「健康程度」,我開發了這套 3x3 分佈矩陣分析引擎: 橫向維度(時
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
本文說明在安裝實體具有多核 GPU 的環境下,可以透過 Python 「多執行緒的」程式,讓 CPU 及 GPU 依照特性,各自同時進行運算,得到最好的算力配置。
Thumbnail
本文說明在安裝實體具有多核 GPU 的環境下,可以透過 Python 「多執行緒的」程式,讓 CPU 及 GPU 依照特性,各自同時進行運算,得到最好的算力配置。
Thumbnail
你是怎麼在用 AI 工具的呢? 回頭看這幾年 AI 的發展歷程,我們從最早期的文字接龍,一路見證了全方位數位助理的誕生。中間經歷了無數次的技術變革,從 Text-to-Text 的文本生成,到跨越感官的 Text-to-Image、Video 與 Audio。而今,這項技術迎來了最關鍵的轉折點「A
Thumbnail
你是怎麼在用 AI 工具的呢? 回頭看這幾年 AI 的發展歷程,我們從最早期的文字接龍,一路見證了全方位數位助理的誕生。中間經歷了無數次的技術變革,從 Text-to-Text 的文本生成,到跨越感官的 Text-to-Image、Video 與 Audio。而今,這項技術迎來了最關鍵的轉折點「A
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
Thumbnail
《轉轉生》(Re:INCARNATION)為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,結合拉各斯街頭節奏、Afrobeat/Afrobeats、以及約魯巴宇宙觀的非線性時間,建構出關於輪迴的「誕生—死亡—重生」儀式結構。本文將從約魯巴哲學概念出發,解析其去殖民的身體政治。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News