Observing that TCP lacks message boundaries on localhost

ネットワーク・RFCカテゴリを表すパンダのイラスト Networking / RFC

About this article
This article was created using an automated generation workflow powered by generative AI. After reviewing RFC 9293 and official Microsoft Learn documentation for TcpClient, we observe TCP byte streams on localhost and organize the design of boundaries required in actual protocols.

Verification Status: 📘 Official Specifications Confirmed, Execution Unverified

In TCP, even if the sender calls Write twice, there is no guarantee that the receiver will get them in two separate parts. This is because TCP handles an ordered byte stream, not a sequence of messages.

Without knowing this difference, it can lead to bugs such as JSON occasionally being cut off in the middle or two pieces of data sticking together.

Try it first

Open two PowerShell windows.

Receiver:

$l = [Net.Sockets.TcpListener]::new(
    [Net.IPAddress]::Loopback,
    50555
)

$l.Start()
$c = $l.AcceptTcpClient()
$s = $c.GetStream()

$b = New-Object byte[] 1024
$n = $s.Read($b, 0, $b.Length)

[Text.Encoding]::UTF8.GetString($b, 0, $n)

$s.Dispose()
$c.Dispose()
$l.Stop()

Sender:

$c = [Net.Sockets.TcpClient]::new('127.0.0.1', 50555)
$s = $c.GetStream()

foreach ($x in 'HELLO', 'WORLD') {
    $b = [Text.Encoding]::UTF8.GetBytes($x)
    $s.Write($b, 0, $b.Length)
}

$s.Dispose()
$c.Dispose()

Sometimes it appears as HELLOWORLD, but other times a single Read may only retrieve part of it.

Send count and receive count do not correspond

sequenceDiagram
  participant C as Client
  participant T as TCP byte stream
  participant S as Server
  C->>T: Write "HELLO"
  C->>T: Write "WORLD"
  T-->>S: Read "HELLOWORLD" のこともある
  T-->>S: Read "HEL" + 次のReadで残り のこともある

TCP guarantees "order" and "reliability," not the write boundaries made by the application.

Try setting the buffer to 3 bytes

By shrinking the receive buffer to 3 bytes, you can visibly see that a single Read cannot retrieve the whole thing.

$b = New-Object byte[] 3

This experiment shows that designing under the assumption that "one Read completes one message" is dangerous.

How to establish boundaries in real protocols

There are three representative methods.

MethodExampleCharacteristics
DelimiterOne item up to a newlineSuited for text
Fixed lengthAlways 128 bytesSimple but low flexibility
Length prefixBody length in the first 4 bytesSuited for binary/APIs

For example, with newline separation, instead of converting to a string every time you Read, you accumulate data in the receive buffer and extract up to the point where a newline arrives as a single unit.

How it can be applied in practice

  • TCP socket communication

  • Custom protocols

  • Fixed-length messages

  • Device communication

  • JSON or CSV flowing over TCP

  • Integration with legacy enterprise systems

Simply stating that "it could be received in a single attempt every time in the test environment" is not grounds for a correct implementation. Changes in traffic volume, the OS, network conditions, and transmission timing can alter the split units.

Points to note

  • Read() The return value n represents the number of bytes actually received

  • The buffer size is not necessarily filled to the maximum

  • Read() = 0 is an important state indicating the end of a connection

  • Because UTF-8 characters span multiple bytes, character boundaries must also be considered

  • Determine the maximum message length in production protocols

Summary

  • TCP is a byte stream and does not preserve message boundaries

  • Write counts and Read counts do not match

  • Boundary rules are required on the application side

  • Use newlines, fixed lengths, length prefixes, etc.

  • Properly handle Read return values and connection termination

Official and Primary Sources

Document information

Article title
Observing that TCP lacks message boundaries on localhost
Published
Updated
Source
https://papanda925.com/?p=15402&lang=en

License: Text and original figures for which this site holds the relevant rights are available under CC BY 4.0 , unless otherwise noted. This article may include content created or edited with generative AI. If code has a separate license notice or a linked GitHub repository license, that license takes precedence for the code. Quotations, third-party materials, images, and trademarks are excluded from this license. Usage policy

Copied title and URL