Memra

Reading from a server: a line-protocol client

◈ 5 cards

Read the protocol off the wire with telnet first, then transcribe it into Java: a daytime client with an explicit charset, a real read loop, and SO_TIMEOUT set before the first read.

Read the protocol off the wire before you write any Java

The sockets are easy. The protocols are what make network programming hard, and the fastest way to learn one is to speak it by hand. telnet opens a raw TCP connection to any host and port, sends whatever you type, and prints whatever comes back. Point it at a server, watch the exchange, and the Java client becomes transcription rather than invention.

This is not a beginner's crutch — it stays useful forever. It is how you tell "my client is broken" from "the server is broken", and it is how you will acceptance-test the protocol server you build in Module 9. Do it first, every time.

Daytime: the smallest protocol there is

The daytime protocol (RFC 867) listens on TCP port 13. It has no commands. You connect; the server sends a human-readable date and time; the server closes the connection. That is the entire specification, which makes it the right place to meet the read side of a socket without a protocol getting in the way.

Run telnet time.nist.gov 13 and you will see the connection open, one line of text arrive, and the connection close. Three facts fall out of that transcript, and all three become code:

  1. The client never writes. So you only need the input stream.
  2. The message ends when the connection ends. The framing rule here is end-of-stream, not a terminator character.
  3. The text is ASCII. So the charset is a known constant, not the platform default.

Bytes are not characters, and a read is not a message

getInputStream() gives you bytes. To get text you wrap it: new InputStreamReader(in, StandardCharsets.US_ASCII), and usually a BufferedReader on top so you can call readLine(). Always state the charset. A reader constructed without one uses the machine's default encoding, which means your program's behaviour depends on whose laptop it runs on — the classic works-here-fails-there network bug.

End-of-stream is signalled two ways depending on the layer you are reading at: InputStream.read() returns -1, and BufferedReader.readLine() returns null. Both mean the same thing — the peer closed (or half-closed) its side and no more data is coming. Neither is an error.

And never assume one read() returns one message. TCP is a byte stream; a 200-byte reply can arrive as one chunk or as five. You loop until the framing rule you identified in the transcript says stop.

Set the timeout before you read, not after

By default a socket read blocks forever. A server that accepts your connection and then simply stops talking — crashed, wedged, overloaded — will hang your client permanently, with no exception and no CPU use to show for it. setSoTimeout(15_000) caps each individual read at 15 seconds; when it expires you get a SocketTimeoutException and, importantly, the socket is still connected, so you may retry the read. Set it immediately after connecting, before the first read.

Worked example — a daytime client

Put the three transcript facts together: connect to port 13, cap the read, wrap the input stream in an ASCII reader, and loop readLine() until it returns null. Seven lines, and it is a complete, correct client for a real internet protocol.

replytranscribetelnet host 13speak it by handone line + EOFthe framing rulereadLine() loopuntil nullDebug the protocol before you write the client.
The middle box is the work. Once the transcript tells you the reply is one line ended by the server closing, the Java read loop is determined: read lines until readLine() returns null.
NORMAL ~/memra/learn/comp-348/line-protocol-client utf-8 LF