位元組串流服務(byte-stream service)
當你把水從一個杯子倒進另一個杯子,你不會把它倒成一顆顆編了號的小水滴——它就是連成一股連續的水流。TCP 對它的資料也是這樣:對應用程式而言,一條 TCP 連線看起來像一股從寄件者可靠地流向接收者的連續位元組串流,而不是一連串分開的訊息。你在一端寫入位元組,它們會以相同的次序從另一端流出。
這在實務上的意思是:TCP 不保留訊息邊界。如果你的程式呼叫三次「送出」、各送 100 位元組,接收端可能一次就讀到全部 300 位元組,或分兩次各讀 150,或一個位元組一個位元組地讀——TCP 只承諾位元組正確且依序到達,不承諾維持你送出時的分組方式。底層中,TCP 為了傳輸把串流打包成區段並替每個位元組編號,但應用程式從不看到那些區段邊界;它只看到一股依序的流。
為什麼重要:位元組串流對程式設計者來說好寫到不行,但它把一項責任推給應用程式——訊息框架化(message framing)。如果你的協定要送一個個離散訊息,你就得自己標出每個訊息在哪裡結束(例如用長度前綴,或像換行符這樣的分隔符),因為 TCP 不會幫你做。這與 UDP 相反,UDP 是訊息導向的:每個 UDP 資料報都是一個自成一體、邊界被保留的訊息。把 TCP 的串流當成一個個訊息,是經典的初學者臭蟲——讀一次就假設拿到了完整訊息。
一個聊天程式在一條 TCP 連線上先送「Hello」再送「World」。接收端可能一次就讀到「HelloWorld」,也可能讀到「Hel」再「loWorld」。要還原這兩個訊息,應用程式必須替它們框架化——例如先送長度,或在每則訊息結尾加上換行符。
TCP 依序傳遞位元組,但不保留你的訊息邊界。
最常見的初學者錯誤:把一次 TCP 讀取當成一個訊息。串流沒有內建邊界——框架化是應用程式的工作。相對地,UDP 會把每個資料報保留成一個離散訊息。