訊息框架化(message framing)
如果 TCP 交給你一道又長又連續、沒有斷點的位元組串流,你怎麼知道一則訊息在哪結束、下一則從哪開始?這就像收到一段沒有空格也沒有標點的文字——你需要某種約定好的規則把它切成詞。訊息框架化正是那個約定好的規則:寫進你應用協定裡的慣例,用來標記位元組串流中每則邏輯訊息的邊界。
有兩種經典技術。第一種是長度前綴:每則訊息之前先寫上它的大小,比方一個 4 位元組整數,於是接收端先讀那 4 位元組、得知訊息是 N 位元組長,然後恰好再讀 N 個位元組——不必猜。第二種是分隔符:你在每則訊息結尾放一個資料內不會出現的特殊記號,例如以行為單位的協定用換行符,接收端就一直讀到看見那個記號為止。許多真實協定混用各種想法:HTTP/1 用以換行分隔的標頭區段,再用 Content-Length 標頭(一種長度前綴)標示本文。接收端必須迴圈累積位元組直到湊滿一個框架,因為單一次 recv 可能交付一則不完整的訊息,或一次交付好幾則。
為什麼重要:框架化不是可有可無的裝飾——沒有它,以 TCP 為基礎的協定根本就是壞的,因為位元組串流抽象抹掉了你的邊界。做錯了,你就會讀到一則訊息的一半外加下一則的開頭,把之後的一切都弄亂。框架化也有安全分量:盲目相信長度前綴,會讓攻擊者送一個巨大的數字,逼你配置龐大的記憶體,所以穩健的程式會限制框架的最大尺寸。分隔符框架化必須處理記號出現在酬載內部的情況(透過跳脫),否則遇到合法資料就會損毀。
長度前綴框架化:要送 "hello"(5 位元組),你先寫 4 位元組的長度 5,再寫那 5 個位元組。接收端讀 4 位元組(得到 5),然後恰好再讀 5 個——便知道它收到一則完整訊息,無論底層串流被 recv 怎麼拆。
長度前綴或分隔符——擇一,好讓接收端能切分串流。
務必把長度前綴限制在合理的最大值。盲目按發送端宣稱的尺寸配置記憶體,是經典的阻斷服務漏洞:一則說「長度 = 4 GB」的訊息就能耗光你的記憶體。