Question
· Jul 17

How to handle a TCP/IP Response without terminator character using EnsLib.TCP.TextLineOutboundAdapter

Hello everyone,

I'm using EnsLib.TCP.TextLineOutboundAdapter to communicate with a third-party system over TCP/IP. The issue is that the system sends back only an integer (e.g. 1001 or -1) without any terminator (like $c(10)).

The adapter expects a terminator and always times out with ErrTCPTerminatedReadTimeoutExpired, even though the correct data is received. Here an example of an error: 
[TCPSender] Errore nell'invio: ERROR <Ens>ErrTCPTerminatedReadTimeoutExpired: TCP Read timeout (15) expired waiting for terminator 0, data received ='1005'

Trying different terminators (e.g.  $c(0), $c(13)) didn’t work.
I’d like to know if there’s a way to disable terminator checking or manually read the entire response without waiting for an end character.

Thanks in advance!

Enrico

Product version: IRIS 2023.1
$ZV: IRIS 2023.1.2.450.0
Discussion (3)3
Log in or sign up to continue

To address the behavior of the EnsLib.TCP.TextLineOutboundAdapter, where it expects a terminator and times out if none is provided, you have a few options:

  1. Explicitly Set a Terminator:
    You can set the Terminator property of your adapter to a character or sequence of characters that you might expect (though you already attempted $c(10) or $c(13) without success). According to the documentation, this property supports multi-character strings [1].

    Example of code customization:

    Class Custom.TCPAdapter Extends EnsLib.TCP.TextLineOutboundAdapter
    {
       Property Terminators As %String [ InitialExpression = "" ];  // Clear terminators if none should apply
    }
    
  2. Custom Adapter or Manual Reading Logic:
    If the responses truly do not include terminators and cannot be adjusted on the third-party side, you might need to implement your own logic for receiving data. This involves overriding the necessary methods in the adapter to change how responses are interpreted — possibly using a timeout or a custom data parse handler to disconnect terminator reliance.

    Example of using a manual read logic:

    Method ReadWithoutTerminator()
    {
       // Example of binary mode read without terminators
       set device = "|TCP|Host:Port"
       open device:("R")
       use device
       read x:Timeout
       quit x
    }
    
  3. Binary Stream Mode:
    You could configure the adapter to operate in binary mode (/IOT="RAW"). Manually process the data reading and assembly based on expected response patterns or sizes [2][3].

    Example:

    set device="|TCP|7000"
    open device:(host:port:"M")
    use device:(/IOT="RAW")
    read response:Timeout
    

You should consider adapting the built-in EnsLib.TCP.TextLineOutboundAdapter or creating a subclass of it for better control over edge-case behaviors. [4][2][3]

Sources:

I wonder how you expect to know that your input is complete without any terminator.
And according to your example, you also don't have a fixed length:
Withoit an clear signal timeout seems to be the only way to know you are complete.

You may read input character by character without guarantee  
how do decide for 1 or 10 or 100 or 1000  ?
Some ending character (eg. not numeric) or a fixed length is required

you could try to set your terminator to null String "". 
it is optional accordig to docs
https://docs.intersystems.com/iris20251/csp/docbook/DocBook.UI.Page.cls?KEY=GIOD_tcp#GIOD_tcp_open

  • terminators

Optional — A list of up to eight user terminator characters that will terminate reads on the TCP binding device. If you specify both T mode and terminators at the same time, T mode is ignored.