Skip to main content
Version: 1.0.8

TCP / UDP

For equipment that has no industrial protocol at all: bench scales, barcode and RFID readers, weather stations, laboratory instruments, serial devices behind an Ethernet gateway, and in-house protocols. QUBIQ opens the socket, splits the byte stream into messages, and lets you map fields to tags.

Configuration​

FieldDescription
NameConnection identifier.
HostDevice IP or hostname (for client role).
PortDevice port, or the port to listen on in server role.
Transporttcp or udp.
Roleclient — QUBIQ connects out. server — QUBIQ listens and the device connects in.
Frame modeHow the byte stream is split into messages. See below.
DelimiterFor delimiter framing: the terminator, e.g. \r\n, \n, \x03.
Frame sizeFor fixed-length framing: bytes per message.
Max message bytesHard cap; a message larger than this is not buffered indefinitely. It ends that stream and is reported.
Field delimiterSplits a message into fields, e.g. , for CSV, \t, ;.
Field countExpected number of fields. A message with a different count turns its tags Bad.
WriteableAllows tags on this connection to send data to the device.
Connect timeout (ms)Socket connect timeout.
Inactivity timeout (ms)Reconnect if nothing is received for this long.

Framing​

A TCP stream has no message boundaries — framing is how you recover them. Getting this wrong is the usual cause of "half a reading" or "two readings stuck together".

Frame modeUse whenNotes
DelimiterThe device terminates each message (\r\n, \n, ETX)The most common case.
Fixed lengthEvery message is exactly N bytesBinary protocols with a fixed record.
NoneUDP, where each datagram is already a messageDo not use for TCP.

UDP preserves datagram boundaries, so framing is usually unnecessary — but UDP also loses datagrams silently and may reorder them. Do not use it for anything you must not miss.

A message cut short is refused, not published Changed in 1.0.7​

When a TCP stream ended in the middle of a message — the device dropped, or closed the socket — the bytes received so far used to be handed on as if they were a whole message, and published as a tag value with Good quality. A short reading looked exactly like a real one.

The fragment is now discarded and the reason reported:

Frame modeRefused at the end of a stream
Fixed lengthFewer bytes than the frame size.
DelimiterAny bytes after the last delimiter.

The delimiter case has a consequence worth checking. A complete message with no terminator cannot be told apart from a truncated one, so a device that sends its last message without the delimiter and then closes the connection now loses that message, where it used to arrive. If a device does that, it is not terminating its messages the way its framing says — confirm the delimiter against a raw capture.

Framing faults are reported Changed in 1.0.7​

A message longer than Max message bytes, a stream cut mid-message and a read error all stop the stream, and until 1.0.7 none of them said so: the connection simply went quiet, or one peer of a server silently disappeared. Now:

  • In client role the connection is marked down with the reason — framing: … rather than a bare disconnected — and reconnects.
  • In server role only the offending peer is dropped. The fault is logged and counted as a failure on the connection, but the listener stays up and the other peers' tags stay Good: one device sending a malformed stream must not mark every tag on the listener Bad.

Field mapping​

Every connection gets a fixed set of generated tags, and a binding's address picks one of them by name:

Generated tagHolds
messageThe whole message, as text.
messageBytesThe whole message, as hexadecimal.
lastReceiveTimeWhen the message arrived.
field0 … fieldNOne per field, counted from 0, when a field delimiter and field count are set.
writeable, writeableBytesWrite-only: what a write sends to the device. TCP with Writeable on only.
Message: "ST,GS,+ 12.345,kg
"
Fields: field0="ST" field1="GS" field2="+ 12.345" field3="kg"

Tag Scale/Status → field0
Tag Scale/Weight → field2 (data type float)
Tag Scale/Unit → field3

Field count is a cheap integrity check: a truncated or concatenated message has the wrong number of fields. It is not parsed into wrong tags: every tag of that message goes Bad, with the counts in the status (field count 3 does not match expected 4).

Binding tags​

FieldNotes
TagOne of the generated tags, chosen from a list. The field tags appear once the connection has a field count.
Data typeSet it — text "12.345" becomes a number only if the tag says float.

There is no poll rate: every message the device sends updates the tags.

Writing to the device​

With Writeable enabled on a TCP connection, writing a tag bound to writeable (text) or writeableBytes (hexadecimal) transmits the value on the socket; any other generated tag refuses a write. The tag then shows the last value sent, since nothing reads it back. The framing configuration is applied on the way out: the delimiter is appended, or the payload is padded to the fixed length.

Use this for command protocols — tare a scale, trigger a reader, request a measurement.

In server role a write goes to the most recently connected peer that is still connected. 1.0.7 It used to go to the most recent peer ever — so once that peer left, every write failed until another connected, even with other peers live on the listener.

Reconnecting Changed in 1.0.7​

In client role a dropped connection is redialled with backoff, from half a second up to fifteen seconds between attempts, and there is always a wait before a redial.

The backoff now resets only after a connection has lasted five seconds. It used to reset on any successful dial, so a peer that accepted and immediately hung up — the wrong port, the wrong protocol, a device at its connection limit — was redialled with no delay at all: thousands of connection attempts a second at one end, a pegged CPU at the other.

Requests to the worker — a connection check, a write — are also handled side by side across connections now, so one unreachable device no longer holds up the others.

Quality and liveness​

A raw socket gives no quality information, so QUBIQ infers it:

ConditionQuality
Message parsed, field presentGood
Socket down or reconnectingBad
Field count does not matchBad on every tag of the message, with the counts
Message over Max message bytesStream ended and reported
Stream ended mid-messageFragment discarded, never published
Nothing received within the tag's stale after 1.0.8Uncertain, last value kept

For a device that sends on a cycle, set stale after on its tags. Without it, a dead device is indistinguishable from a quiet one.

Security​

Raw TCP/UDP has no authentication and no encryption. Anyone who can reach the port can send data that QUBIQ will parse into tags.

  • Keep these devices on an isolated segment.
  • In server role, bind to a specific interface and firewall the port.
  • Never expose a server-role TCP/UDP connection to an untrusted network.
  • Treat values from it as untrusted input: validate ranges on the tag, not just in the display.

Troubleshooting​

SymptomCheck
Values are truncated or concatenatedWrong frame mode or delimiter. Capture the raw stream and look at the actual terminator.
Some messages ignoredField count mismatch — the device emits a status message with a different shape.
Data stops after a whileDevice closed the socket; set inactivity timeout so QUBIQ reconnects.
Nothing at all, client roleThe device may be a server-only device expecting QUBIQ to listen — switch roles.
Numbers arrive as stringsSet the tag's data type; leading spaces and + signs are handled on conversion.
Works then breaks after a firmware updateVendors change delimiters and field order between versions. Re-capture.
Connection status reads framing: …A message over Max message bytes, or a stream that ended mid-message. See framing faults.
A device's last message before it disconnects no longer arrivesIt is sent without the delimiter, and is now refused as a partial frame.
Writes fail in server role while a peer is connectedFixed in 1.0.7 — writes follow the most recent live peer.

Next​

→ SQL databases