In JMeter's TCP Sampler, what decides when the response read stops?
answer
- Something must say the reply ended
- A pluggable class owns the framing
- The shipped default switches the check off
- 1000 is not a byte value
basics
~20 sThe chosen TCPClient class. TCPClientImpl stops at the end-of-line byte if one is set, otherwise only when the stream ends. None is set by default, so a server holding the socket open makes every read wait out the response timeout.
solid answer
~40 sThe **TCP Sampler** delegates framing to a handler class, picked from the **TCPClient classname** field, failing that the `tcp.handler` property, failing that `TCPClientImpl`. `TCPClientImpl` reads until it sees the end-of-line byte, and if none is defined it reads until the stream ends. The default of `tcp.eolByte` is `1000`, deliberately outside the `-128..127` byte range, which switches EOL checking **off**. Against a server that holds the connection open there is then no stream end to reach, so the read blocks until the response timeout — applied as `Socket.setSoTimeout` — fires. The sampler reports response code `500` with whatever partial bytes it had. `BinaryTCPClientImpl` frames on `tcp.BinaryTCPClient.eomByte` instead; `LengthPrefixedBinaryTCPClientImpl` reads a length prefix whose width comes from `tcp.binarylength.prefix.length`, default `2` bytes.
code
properties · 7 lines# user.properties - all of these ship commented out in bin/jmeter.properties
tcp.handler=TCPClientImpl
tcp.eolByte=10
tcp.charset=UTF-8
tcp.status.prefix=Status=
tcp.status.suffix=.
tcp.binarylength.prefix.length=2go deeper
Recall that a TCP Sampler needs to be told where a response ends, and that the end-of-line byte is not set for you.
Explain the three shipped TCPClient implementations and which property each one frames on, including why the default 1000 disables the check.
Diagnose from the symptom: identical elapsed times equal to the response timeout, code 500, and partial response data all point at framing rather than at the server.
Decide whether a protocol deserves a shared custom TCPClient class maintained as a build artefact, or whether the team should not be driving it over raw sockets at all.
A TCP Sampler pointed at an order-status feed will happily report four-second samples on a service that answers in five milliseconds. Nothing is slow. The sampler simply does not know the reply has finished. ## The sampler owns the socket; the handler owns the framing The TCP Sampler opens the socket, writes **Text to send**, and hands the input stream to a handler class. That class decides where one response ends. The class is resolved in this order: 1. the **TCPClient classname** field on the sampler (or on a **TCP Sampler Config** element); 2. failing that, the `tcp.handler` property; 3. failing that, `TCPClientImpl`. An unqualified class name is retried inside the package `org.apache.jmeter.protocol.tcp.sampler`, which is why `BinaryTCPClientImpl` works as a bare name. Three implementations ship: | Implementation | Where it stops reading | |---|---| | `TCPClientImpl` | at the end-of-line byte if one is defined, otherwise at the end of the stream | | `BinaryTCPClientImpl` | at the end-of-message byte from `tcp.BinaryTCPClient.eomByte`, otherwise at the end of the stream | | `LengthPrefixedBinaryTCPClientImpl` | after the number of bytes given by the message's own binary length prefix | `BinaryTCPClientImpl` also changes the *input*: the text you type is treated as a hex-encoded string and converted to binary, and the response is converted back. ## Why the default is a trap `TCPClientImpl` takes its end-of-line byte from `tcp.eolByte`, whose default is `1000`. A byte cannot be `1000`. That value is chosen precisely so it falls outside `-128..127`, and the client's setter reads that as *no EOL byte* and turns the check off. So out of the box the only thing that ends a read is the end of the stream — that is, the peer closing its side. That works for a one-shot protocol where the server closes after answering. It fails for exactly the protocols people reach for the TCP Sampler to test: line-oriented feeds, length-framed binary protocols, anything that keeps the connection open for the next request. The read blocks, the response timeout expires, and you get: - an elapsed time pinned at the timeout value on every single sample, - response code `500` with the exception in the response message, - the partial bytes that *did* arrive still stored as response data, which is why the sample looks like it half worked. ## Fixing it - Set the sampler's **End of line(EOL) byte value** field, or the `tcp.eolByte` property, to the real terminator — `10` for a newline-delimited feed. The field wins over the property when both are set. - For a binary protocol with an end marker, switch the handler to `BinaryTCPClientImpl` and set `tcp.BinaryTCPClient.eomByte`. - For a length-framed protocol, use `LengthPrefixedBinaryTCPClientImpl` and set `tcp.binarylength.prefix.length` if the prefix is not two bytes. - If none of the three frames your protocol, write a class implementing `org.apache.jmeter.protocol.tcp.sampler.TCPClient` — usually by extending `AbstractTCPClient` — and name it in the sampler. - Keep the response timeout generously above the real reply time. It is a backstop, not a framing mechanism, and a timeout set too tight will truncate a legitimate read. ## The other switches on the panel **Re-use connection** shares one socket between samplers in the same thread, keyed on the exact host string and port, so different threads and different host spellings get different sockets. **Close connection** closes the socket after the sampler even when reuse is on, which is what you want at the end of a thread loop. An error always closes the socket. **SO_LINGER** set to `0` avoids piles of sockets in `TIME_WAIT`. **Set NoDelay** disables Nagle's algorithm. Finally, the response code does not come from the protocol. If `tcp.status.prefix` is set, JMeter pulls the text between that prefix and `tcp.status.suffix` out of the response body and uses it as the sample's response code, resolving it to a message through `tcp.status.properties` when that file is supplied. If the prefix is configured but no such status is found in the response, the sample fails with code `999` and the message `Status value not found`.
- The sampler's EOL field and the tcp.eolByte property are both set. Which wins?The sampler's **End of line(EOL) byte value** field. The handler is constructed with the property's value, then the sampler overrides it from the element if that field is non-empty. So the property is the fleet-wide default and the field is the per-element exception — which is the right way round for a plan that has to run on machines you did not configure.
- What response code does the TCP Sampler give when its response timeout expires mid-read?`500`, with the exception's text as the response message and the bytes read so far kept as response data. The partial data is the giveaway: a sample that failed but still carries a plausible-looking response almost always means a framing problem rather than an unreachable server.
- How would you frame a length-prefixed binary order protocol with the TCP Sampler?Set the handler to `LengthPrefixedBinaryTCPClientImpl`, which extends the binary client by prefixing outgoing message data with a binary length and reading incoming messages by that prefix. The prefix defaults to two bytes and is changed with `tcp.binarylength.prefix.length`. The text you type is still hex-encoded, as with the plain binary client.
Reading with no end-of-line byte is like waiting for someone to hang up before you accept that they have finished a sentence. If they stay on the line, you sit there until the egg timer goes off and then write down that the call failed.
saying these in an interview costs you the question
- Assuming the sampler stops reading when the server stops sending
- Believing tcp.eolByte defaults to a newline
- Raising the response timeout to fix pinned sample times
- Expecting a status code without configuring tcp.status.prefix
- Typing plain text into a sampler using the binary client