Checkpoint Lab — JMS, FTP, LDAP, TCP, and Other Protocol Test Patterns
The checkpoint proves that a non-HTTP performance experiment is valid only when the connection/message lifecycle is explicit. The target is the local TCP fixture; the second-protocol exercise is a JMS request/reply architecture that requires no broker installation.
Learning objectives
- Run a safe local TCP request/reply experiment with explicit line framing.
- Predict and verify socket demand under persistent versus per-sample connection policies.
- Correlate response connection/request IDs and assert framed replies.
- Compare a controlled 25 ms server delay with client-observed elapsed time.
- Verify all TCP connections close and no target state accumulates.
- Design—but do not require—the equivalent JMS request/reply topology with provider/correlation/cleanup rules.
1. Exact assumptions and hard ceilings
| Item | Checkpoint baseline |
|---|---|
| JMeter | Apache JMeter 5.6.3. |
| Java | Java 17 JDK; JMeter 5.6.3 requires Java 8+. |
| Plugins/provider JARs | None for mandatory TCP path. |
| Fixture |
prompt17-tcp-line-fixture-v1, Python standard
library.
|
| Target | 127.0.0.1:9100 only. |
| TCP client | Built-in TCPClientImpl. |
| Framing | Request appends LF; response EOL byte=10. |
| Threads | 2 maximum. |
| Loops | 5 maximum per profile. |
| Timeouts | Connect=500 ms; Response=1000 ms. |
| Synthetic delay | 25 ms measured exercise; fixture hard cap=100 ms. |
| Profiles | persistent reuse=true, then per-sample reuse=false; separate evidence directories. |
| JMS second protocol | Architecture design only; no broker/provider required. |
2. Setup and target authorization/preflight
-
Start
tcp_line_fixture.pyon 127.0.0.1:9100 with a fresh JSONL log. - Run one manual PING client and archive/clear that preflight event file before measured runs.
- Record Python version, JMeter 5.6.3, Java version, fixture version/listen address.
- Verify no other process/endpoint is used.
3. Persistent checkpoint tree
Test Plan
├── TCP Sampler Config
│ TCPClientImpl
│ 127.0.0.1:9100
│ Re-use connection=true
│ Close connection=false
│ EOL=10
│ Connect Timeout=500ms
│ Response Timeout=1000ms
└── Thread Group — 2 threads × 5 loops
├── TCP Ping A
│ Text=PING|T${__threadNum}-${__time()}|hello-${__threadNum}${__char(10)}
│ └── RegEx Extractor CONN_A = CONN=([^|\r\n]+)
└── TCP Echo B
Text=ECHO|T${__threadNum}-${__time()}|second-${__threadNum}${__char(10)}
└── assert response contains CONN=${CONN_A}
4. Predictions before persistent run
Prediction A — connections: the two JMeter threads should open approximately two fixture connections and reuse them for all 20 request/reply samples.
Prediction B — isolation: each thread's Ping A and Echo B response within a loop should report the same connection ID; different threads should normally have different connection IDs.
Prediction C — cleanup: JMeter closes sockets when the test ends, so fixture disconnect count should eventually match measured connection opens and active connection count return to zero.
5. Run persistent profile
jmeter.bat -n `
-t plans\checkpoint-tcp-persistent.jmx `
-l results\persistent\results.jtl `
-j results\persistent\jmeter.log `
-e -o results\persistent\report
Record generator CPU/memory/socket count during the run. Keep the fixture event log for this profile separate.
6. Verify persistent predictions independently
python tools/analyze_tcp_events.py results/persistent/tcp-events.jsonl
Require:
- 20 request events;
- approximately 2 measured TCP connections;
- multiple requests per connection;
- max active connections ≤2;
- no duplicate request IDs/ERR statuses;
- JTL zero unexpected failures.
7. Change one variable: disable connection reuse
Duplicate the exact JMX and uncheck Re-use connection. Keep target, threads, loops, payloads, EOL, timeouts, and assertions unchanged. Start a fresh fixture log.
Prediction D: approximately 20 measured TCP connections are opened—roughly one per sampler—while total request count remains 20.
8. Run and compare per-sample profile
jmeter.bat -n `
-t plans\checkpoint-tcp-per-sample.jmx `
-l results\per-sample\results.jtl `
-j results\per-sample\jmeter.log
Compare connection opens, max active sockets, elapsed distribution, generator/socket state, and server event counts. Do not call any timing difference “TCP server capacity”; the experiment only changes client connection lifecycle under tiny local load.
9. Request/reply timing proof
Run a separate 1-thread ×5-loop profile:
DELAY|T${__threadNum}-${__time()}|25${__char(10)}
Prediction E: each response reports
DELAY_MS=25 and JMeter elapsed is at least
approximately 25 ms plus loopback/client overhead. Preserve fixture
service_wall_ms so client/server timing can be
compared.
10. Verify target cleanup
After each profile, wait briefly for JMeter sockets to close, then verify event log connect/disconnect parity and zero active connections. Stop the fixture only after verification.
The protocol has no persistent messages/files/database rows, so socket closure and event-log completion are the target cleanup contract.
11. Second-protocol architecture — JMS request/reply
Design the equivalent experiment without executing it:
| TCP checkpoint concept | JMS request/reply equivalent |
|---|---|
| Connection/socket ID | Provider connection/session/client identity. |
| Request ID echoed by target | JMSCorrelationID or provider-approved correlation property. |
| Line-framed reply | Reply message on dedicated reply queue. |
| Persistent socket versus per-sample | Connection/session reuse versus reconnect setup policy. |
| No leftover TCP state | Request/reply queue depth returns to baseline; temporary/run-scoped queues cleaned. |
| Server event log | Broker/service message timestamps, queue depth, consumer processing log. |
Minimum provider prerequisites if later executed: pinned matching
provider/JNDI JARs in every JMeter injector lib, JMeter
restart, localhost/private authorized broker, synthetic credentials,
run-scoped destinations/IDs, explicit reply timeout, and cleanup
verification.
12. JMS predictions before any future run
JMS Prediction 1: Request Only can show successful low send latency even if reply/consumer processing never occurs; queue depth/consumer telemetry must reveal that.
JMS Prediction 2: Request Response cannot complete successfully until the configured reply/correlation path produces a reply or timeout occurs.
JMS Prediction 3: missing provider JAR/JNDI class fails on generator setup and should produce no meaningful broker message load.
13. Required evidence packet
| Artifact | Required content |
|---|---|
| Topology | JMeter → 127.0.0.1:9100 TCP fixture; no external target. |
| Versions | JMeter 5.6.3, Java 17, Python version, fixture version. |
| Sampler config | TCPClientImpl, EOL=10, timeouts, reuse flag, exact payload pattern. |
| Persistent evidence | JTL + jmeter.log + connection/request event log + generator state. |
| Per-sample evidence | Separate JTL/log/event log showing connection-count change. |
| Timing evidence | 25 ms DELAY JTL elapsed + server service_wall_ms. |
| Cleanup | Connect/disconnect parity and zero active connections. |
| JMS design | Provider JAR prerequisite, request/reply queues, correlation, client IDs, queue cleanup/telemetry. |
| Validity statement | Direct TCP/JMS protocol metrics are not automatically application end-to-end capacity. |
14. Validity statement
prompt17-tcp-line-fixture-v1 on 127.0.0.1:9100, two
threads executed five loops of two line-framed TCP request/reply
samplers. With TCPClientImpl, LF response framing, and Re-use
Connection enabled, each thread reused its own socket and server
connection IDs remained stable within that thread. A separate
per-sample profile disabled reuse while keeping load/payloads
constant, increasing connection opens while request count remained
unchanged. A 25 ms DELAY profile verified a request/reply timing
boundary against server service timing. All measured sockets
disconnected after each run and no target state accumulated. This
validates TCP framing/connection-lifecycle measurement on a tiny
local fixture; it does not establish production network/application
capacity. The equivalent JMS design would require provider-specific
client/JNDI JARs and correlated request-reply/queue cleanup evidence
before execution.”
15. Verification checklist
- Target exactly 127.0.0.1:9100.
- TCPClientImpl and EOL=10 documented.
- Request strings terminate using
${__char(10)}. - Persistent profile ≤2 connections and 20 requests.
- Per-sample profile ≈20 connections and 20 requests.
- All responses have expected command/request/connection evidence.
- 25 ms delay run has matching client/server timing evidence.
- No unexpected errors/timeouts; no active connections after run.
- JMS second-protocol design includes provider JARs, correlation, reply timeout, queue-depth and cleanup evidence.
16. Cleanup / rollback
- Stop JMeter profiles.
- Verify all TCP connections disconnected.
- Stop
tcp_line_fixture.py. -
Retain JTL/
jmeter.log/event logs until review completes. - Delete only disposable local fixture/result files after review.
- No external broker, FTP server, LDAP directory, provider JAR, plugin, container, credential, or production system was changed.
17. What Chapter 17 adds to the operating model
The production performance-testing operating model now has a protocol-semantics contract: sampler/client/provider version, connection/session lifecycle, payload framing or message/file/directory operation, acknowledgement/reply boundary, unique correlation/client IDs, credential/trust rules, target queue/file/session state, cleanup evidence, generator dependency/classpath state, and protocol-specific interpretation of elapsed/latency are reviewed before results become evidence.
Chapter 18 moves to File Uploads, Downloads, Multipart Requests, and Large Payloads. That chapter returns primarily to HTTP/file-transfer payload mechanics and focuses on body/file size, multipart encoding, generator disk/memory/network cost, hashing/validation, storage cleanup, and safe large-payload workload design.
Knowledge check
What proves the persistent TCP profile reused connections correctly?
Server evidence shows many requests per connection with approximately one connection per JMeter thread, and Echo assertions match the Ping-extracted connection ID.
Why is per-sample connection count an important metric?
Disabling reuse changes connection-establishment/socket lifecycle load even when request count and payload work stay constant.
What independent evidence validates the 25 ms request/reply timing?
The fixture's service_wall_ms/DELAY_MS evidence paired with JMeter sampler elapsed.
Why is a JMS broker not required to complete this checkpoint?
The prompt permits designing the equivalent architecture for a second protocol; TCP provides the mandatory executed non-HTTP experiment.
What is Chapter 18's bridge?
Large file/multipart payload testing builds on protocol connection and cleanup discipline while adding payload-size, disk/memory/network and storage-state concerns.
Official references and version notes
- JMeter Component Reference — TCP Sampler — built-in TCP clients, EOL/binary framing, per-thread connection reuse, timeouts, and socket lifecycle.
- JMeter Component Reference — FTP Request — upload/download behavior, login latency, binary/ASCII modes, and credential storage.
- JMeter Component Reference — JMS Publisher — provider/JNDI dependencies, destinations, persistence, message sources, and provider JAR requirements.
- JMeter Component Reference — JMS Subscriber — queue/topic clients, durable IDs, selectors, receive/listener strategies, and connection lifecycle.
- JMeter Component Reference — JMS Point-to-Point — request-only, request-reply, read, browse, and clear semantics.
- JMeter Component Reference — LDAP Request — Add/Modify/Delete/Search operations and cleanup differences.
- JMeter Component Reference — LDAP Extended Request — bind/session-oriented LDAP operations.
- JMeter Functions — __char — inserts explicit Unicode characters such as LF for TCP text framing.
- JMeter Getting Started — Java requirements and GUI authoring versus CLI execution.
- JMeter Best Practices — non-GUI execution and generator validity.
- Apache JMeter downloads — current stable release and Java requirement.
Version-sensitive statements were rechecked against current Apache
JMeter primary documentation on 2026-09-05. The course baseline
remains Apache JMeter 5.6.3 with a Java 17 JDK;
JMeter 5.6.3 requires Java 8+. TCP Sampler is built in and the
mandatory lab uses its default TCPClientImpl with
explicit LF (EOL byte=10) framing. With connection
reuse enabled, TCP connections are reused only by samplers in the
same JMeter thread that use the exact same host string and port;
different threads use different sockets. JMeter's FTP, LDAP/LDAP
Extended, JMS Publisher/Subscriber/Point-to-Point, and TCP
samplers are currently built in. JMS is different from
TCP/FTP/LDAP because JMeter does not bundle a JMS
provider implementation JAR: provider-specific client/JNDI
libraries must be supplied in JMeter's lib directory
and JMeter restarted. FTP sampler latency is the FTP login time,
not full file-transfer elapsed time. JMS request-only measures the
send-side sample; request-reply waits for a reply from the service
and is the appropriate built-in pattern when request-to-reply
latency is required. LDAP Extended models session operations such
as thread bind/unbind. Core TCP login/password fields are not used
by the supplied TCP clients and any entered password is stored
unencrypted, so the TCP lab leaves them blank.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.