System designTroubleshooting

Socket send hangs at vision camera login: add the string terminator

Your camera answers Telnet but the controller's socket send hangs at login: the command string is missing its line terminator. Append CR LF to every command.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01Why Telnet works and your program does not
  2. 02Symptom and likely causes, ranked
  3. 03The fix: append the terminator to every line
  4. 04Worked example: the first login line to a camera at 192.168.1.100, port 23
  5. 05Set a receive timeout so a hang becomes an error
  6. 06Choosing the controller side of the link
  7. 07Checks before you sign off the integration
  8. 08Where to read next
  9. 09Questions

You connect to the camera's command port, the login prompt arrives, you send the user name — and the program sits at the receive call until you stop it. Open a Telnet session to the same address and port and the login works first try. That combination, Telnet fine and your code stuck, points at one missing detail: the line terminator. Telnet-style command ports treat each command as a line that must end in CR + LF, and a Telnet client adds those two bytes for you when you press Enter. A raw socket send transmits exactly the bytes you hand it and nothing more. This guide shows how to confirm the fault, what to append, how to prove it byte by byte, and how to keep the next protocol mismatch from hanging the line. It is written for anyone wiring a vision system's command port to a robot or PLC controller.

Why Telnet works and your program does not

The command port on a vision system is a line-oriented text service. Its parser collects incoming bytes and treats them as one command only when the byte string ends with the line terminator. On Telnet-style ports the default terminator is CR + LF, ASCII 13 followed by ASCII 10, and some systems also accept NUL, ASCII 0, as an alternative. A few serial-derived protocols end lines with a lone CR. The camera's communications manual names the terminator for your system. If the network settings let you move the command port away from 23, remember that the terminator belongs to the protocol, not to the port number — changing the port changes nothing about the line ending.

A Telnet client is a line-mode tool: when you press Enter, it appends the end-of-line bytes before the string leaves your PC. Your controller's socket send instruction is not line-mode. It transmits exactly the bytes in the string, so five characters of user name arrive, the parser waits for bytes six and seven, no command executes, no prompt is queued, and the next receive call waits. The address, the cable and the camera are all fine, which is what makes this fault so quiet.

Terminator Bytes on the wire Where you meet it
CR + LF 2 — ASCII 13, then ASCII 10 default on Telnet-style command ports
CR alone 1 — ASCII 13 serial-derived text protocols
NUL 1 — ASCII 0 some native-mode command protocols

Symptom and likely causes, ranked

The signature: connect succeeds, the banner or login prompt arrives at the first receive, the first send completes without an error, and the second receive never returns. Work down this list; the first cause explains most cases where Telnet works.

  1. Missing line terminator. The send carried payload only. Test: resend with CR + LF appended. If the camera answers, the fault is closed.
  2. Wrong terminator for this camera. You sent CR + LF where the parser wants a lone CR or NUL. Test: try a single CR, then read the communications section of the manual, which names the terminator and its byte value.
  3. Login lines sent ahead of the prompts. Both strings fired back to back, so the password line lands while the camera is still in the user state and gets dropped. Test: one send, then one receive, every time.
  4. The grammar is one line, not two. Some logins take user and password in a single terminated line. Test: compare your bytes against the login example in the manual, character by character.
  5. It is not the terminator. If the hang happens on the send itself — a long string that stalls partway — the TCP buffer or the send queue is the problem, a different fault with its own fix: see why a large socket send stalls partway and how to loop it.

The fix: append the terminator to every line

Build each command as payload plus terminator and never send a bare line. The variable and call names below are illustrative placeholders — keep your controller's own socket send and receive instructions and their parameter forms.

cmd_line : string = ""                   // illustrative variable, starts empty
cmd_line = "admin" + CHR(13) + CHR(10)   // payload + CR + LF
send(cmd_line)                           // your controller's socket send instruction
reply    : string = receive(5000)        // your receive call, 5000 ms timeout

The test that proves it: send admin + CR + LF and the next receive returns the password prompt inside the timeout; send admin alone and the same receive times out. Nothing else in the program changed, so the two bytes are the whole fix.

Apply the terminator to every line, not only the login: the trigger command and the result request need it too. Read one reply after every send — the reply keeps your sequence in step with the camera's state machine and turns the next mistake into visible text instead of a silent wait.

Worked example: the first login line to a camera at 192.168.1.100, port 23

The inputs, and where each comes from:

  • Payload admin — 5 ASCII characters, the camera's user-name prompt in this login sequence.
  • Terminator CR + LF — 2 bytes, ASCII 13 then 10, the default for a Telnet-style command port.
  • Target 192.168.1.100, port 23 — the camera's command address from the network set-up.
  • Receive timeout 5 s — your commissioning safety net, not a camera figure.

The rule in words: the parser executes a command only when the bytes it holds end with the terminator; a Telnet client appends those bytes on Enter; the socket send instruction appends nothing.

bytes on the wire = payload bytes + terminator bytes with the fix: 5 + 2 = 7 bytes ("admin" + CR + LF) without the fix: 5 + 0 = 5 bytes (parser still waiting for byte 6)

With the fix, the parser counts bytes 1–5 as the user name, reads byte 6 as 13 (CR) and byte 7 as 10 (LF), executes the login and queues the password prompt as its reply. Without them, the receive buffer never holds a complete line: nothing executes and nothing is queued. The send itself succeeds in both cases — TCP delivered every byte — which is why the fault stays hidden until the receive call.

Result: 7 bytes complete the login line, 5 bytes stall it, and on a healthy local link the prompt comes back in milliseconds, far inside the 5 s timeout.

Decision: if Telnet logs in and your code hangs at receive, add the 2-byte CR + LF to every line you send — user name, password, trigger and the rest — and keep the 5 s receive timeout through commissioning, so the next grammar mistake surfaces as a printed timeout error instead of a hung program.

Set a receive timeout so a hang becomes an error

Most socket interfaces expose a receive timeout, as a parameter on the receive call or as a socket option. Set 2–5 s while you commission: long enough for a real prompt, short enough that a fault costs seconds, not a shift. For production, log the reply time on every cycle, take the worst value over a few hundred cycles, and set the timeout near three times that figure. On a timeout, close the socket, log the last prompt you received — the text names the line that failed — then reopen and start the login from the top.

If the camera answers nothing at all from the first frame, the terminator is not your only suspect: start with why a sent string is not received: fix the handshake.

The fix costs nothing in hardware: any controller that runs your socket program, holds a port on the camera's subnet and keeps a second port free for the plant network is enough. Splitting the networks like that also keeps plant traffic out of your packet captures when you are hunting bytes.

The MV-VC3301H-128G66 has five or more LAN ports, four built-in light channels and 8 GB of memory, so camera, plant network and light lines all connect without add-on cards.

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$2,419.00View partBuild a system with it

When the cell adds PoE cameras or more light channels, the MV-VC5525-256G70-NN carries PoE camera ports, eight built-in light channels and 32 GB of memory.

Vision controllersHikrobot MV-VC5525-256G70-NN VC5000 Vision Controller, 12th-I5, 32GB+256G SSD, Supported PCIEMV-VC5525-256G70-NN
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
PoE
PoE camera ports
Light outputs
8 built-in channels
$4,479.00 · quotedView and quoteBuild a system with it

Match port count, memory and processor to the rest of the cell on the vision controllers page.

Checks before you sign off the integration

Run this list once the login works:

  • Capture the bytes. Every command frame on the camera link ends with the manual's terminator, 0D 0A for the default; the frame that hung stops at the last payload character.
  • One reply per send. Log every prompt. The first missing reply names the failing line.
  • Prove the timeout. Remove the terminator on purpose, confirm the receive times out at the set value, and confirm the recovery path closes, reopens and relogs in.
  • Real camera, not only the emulator. If you built the login against a software emulator, rerun the whole sequence on the real camera; an emulator can accept a bare line that the camera rejects.
  • Fifty clean cycles. Login, trigger, result consumed by the robot or PLC, fifty cycles in a row with no hang and no missed reply.

The same login sequence, written out step by step from the controller side, is in socket login between a robot controller and a vision camera. For the return direction — result strings headed back to the controller — see sending string data from a vision system to a robot over TCP, and if the payload is read text rather than coordinates, sending a smart camera's OCR string over TCP covers the output format. More fault-finding guides for the systems side are collected on the systems topic page.

If the login grammar still fights you after the terminator fix, send the manual's command examples through the contact page and we will read the byte sequence with you.

Questions

What byte values are CR and LF?

CR is ASCII 13, hex 0D; LF is ASCII 10, hex 0A. Send them in that order unless the camera manual names a different terminator. Some native-mode protocols terminate with NUL, ASCII 0, hex 00 — a single byte. Count the terminator bytes the manual specifies and append exactly those: two for CR + LF, one for CR alone or NUL.

The manual says commands end with a single CR — what changes?

Append only the CR byte and leave the LF out. On a single-CR protocol the extra LF arrives as an empty line: some parsers answer with an error prompt that desynchronizes your login, some ignore it, and some count it as a command. Log every reply so you can see which of the three is happening, and match the terminator to the manual rather than to habit.

Why does the same login work from a terminal program?

Terminal and Telnet clients are line-mode tools: the Enter key appends the end-of-line bytes before the string leaves your PC, so every typed line is a complete command. Your controller's socket send instruction copies the string byte for byte and adds nothing. The same applies to a serial terminal with an append-newline option switched on — turn such options off when you want to compare raw bytes.

Should the user name and password go in one send?

Only if the manual's login grammar says so. Some systems expect user and password as two prompts answered line by line; others take a single line such as user, space, password, terminated once. Read the reply after every send — the prompt text tells you which state the camera is in, and it turns a grammar mistake into a visible error instead of a silent hang at the receive call.

How do I check the bytes my controller actually sends?

Put a packet capture on the camera link: mirror the switch port the camera uses, or run the capture on the PC that hosts your software emulator. Compare your program's frame with the frame a Telnet session sends for the same login. The working frame ends 0D 0A after the payload; the hanging one stops at the last character. One line in the capture usually settles the whole fault.