Chapter 17Lesson 05~235 minutes

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.

CheckpointPersistent TCPPer-sample socketsCleanupJMS design

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.
Abort: non-loopback target, >2 threads, >5 loops, >2 active connections in persistent profile (after excluding manual preflight), repeated unexpected ERR/timeouts, delay input >100 ms, or generator saturation.

2. Setup and target authorization/preflight

  1. Start tcp_line_fixture.py on 127.0.0.1:9100 with a fresh JSONL log.
  2. Run one manual PING client and archive/clear that preflight event file before measured runs.
  3. Record Python version, JMeter 5.6.3, Java version, fixture version/listen address.
  4. 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

Example: “Using Apache JMeter 5.6.3/Java 17 against the Python-standard-library 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

  1. Stop JMeter profiles.
  2. Verify all TCP connections disconnected.
  3. Stop tcp_line_fixture.py.
  4. Retain JTL/jmeter.log/event logs until review completes.
  5. Delete only disposable local fixture/result files after review.
  6. 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?

Why is per-sample connection count an important metric?

What independent evidence validates the 25 ms request/reply timing?

Why is a JMS broker not required to complete this checkpoint?

What is Chapter 18's bridge?

Next chapter

File Uploads, Downloads, Multipart Requests, and Large Payloads

Chapter 18 focuses on safe payload generation, multipart/file transfer, size/hash correctness, generator I/O/memory, target storage, and cleanup under bounded load.

Official references and version notes

Version and compatibility note

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.