1

I have a Socket connection to an COM-Server ++ from W&T that is connected to the internet and also connected to my PC over Serial-to-USB.

The settings of the COM-Server for TCP outbound communication are:

Activ. Packet Options : disabled
Inactiv. Timeout : 00030
Connect. Timeout : 00300
Disconnect Char : 000
Client: "C"+Addr : disabled
Response Mode : disabled

In my application I read the incoming data of this server like this:

    boolean running = true;
log.info( "{0}: Starting to listen for input data", name );
while ( running )
{
  try
  {
    int charsRead = inputStream.read( buffer );

    if ( charsRead < 0 )
    {
      running = false;
    }
    else
    {
      byte[] received = Arrays.copyOf( buffer, charsRead );
      /** TODO: Call interface of protocol here */
      log.info( "{0}: data received: {1}", connection.getName(), new String( received ) );
    }
  }
  catch ( IOException ie )
  {
    setStatus( ConnectionStatus.FAILURE );
    close();
    /** TODO: Exception handling */
    running = false;
  }
}

If I send:test<CR><LF> from the device the log output I get is:

(terminal1) terminal1: data received: t
(terminal1) terminal1: data received: e
(terminal1) terminal1: data received: st
(terminal1) terminal1: data received: 
(terminal1) terminal1: data received: 

The desired Output however is:

(terminal1) terminal1: data received: test  

Where is my mistake or do I assume a false workflow of the read method of the InputStream?

Nico
  • 1,727
  • 1
  • 24
  • 42
  • 1
    [DOC](https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html) public abstract int read() throws IOException Reads the next byte of data from the input stream public int read(byte[] b) throws IOException Reads some number of bytes from the input stream – mihatel Feb 24 '17 at 09:52
  • Oh ok so he doesn't read till the end. Technically waiting for the while to be finished and then logging out the buffer would return excactly the desired result, am I correct? – Nico Feb 24 '17 at 10:06
  • 1
    Just append what read to an array till it ends, that's all – mihatel Feb 24 '17 at 10:17
  • 1
    Simple answer: A stream provides byte transport only. Anything beyond that, like mapping *messages* to and from bytes, needs to be implemented on top of that. This can be as easy as making sure that every "message" ends with a newline (when a "message" is a single line of text). – JimmyB Feb 24 '17 at 10:32

2 Answers2

4

One simple solution looks like this:

StringBuilder sb = new StringBuilder();

int c;

while ( (( c = inputStream.read() ) >= 0) && (c != 0x0a /* <LF> */) ) {
  if ( c != 0x0d /* <CR> */ ) {
    sb.append( (char)c );
  } else {
    // Ignore <CR>.
  }
}

return sb.toString();

This code keeps reading bytes until the end of a line (or the end of the stream) is found, signalled by the <LF>.

We expect <CR><LF> where <CR> is part of the line separator, so we just ignore any <CR> while collecting all other bytes.

JimmyB
  • 12,101
  • 2
  • 28
  • 44
  • This does what I need :) Thank you and pretty nice Idea to use the inputStream itself to loop. Wonder why I didn't think of that – Nico Feb 24 '17 at 11:41
  • Quick question. I tested this again and found out that the stream closes after around 30 seconds. I appended another while loop around it to continue looping while the socket is still connected to the remote device. This is a dirty hack though in my opinion. So is there a better way to keep the stream always open? – Nico Feb 24 '17 at 13:13
  • "Inactiv. Timeout : 00030" - You may have to *send* something before those 30 seconds run out to let the device know you're still there. Otherwise, the device may assume the connection to be "inactive" and close it. – JimmyB Feb 24 '17 at 13:19
  • Ohhh I feel really stupid now...Today is definitely not my brightest day. I was wondering and wondering since I set the option keepAlive. Thank you :) – Nico Feb 24 '17 at 13:24
0

I don't exactly know this library. But a stream returns what it gets, and noone ensures that it is actually all of it... This might solve your problem: How to read all of Inputstream in Server Socket JAVA

EDIT: You could also try to use an ObjectInputStream (if possible) to get the String as Object.

Community
  • 1
  • 1
kleopi
  • 460
  • 3
  • 13
  • I am just using `java.net.Socket` and this socket has an InputStream you get get and the class is `java.io.InputStream`, so it's basically vanilla Java. I just thought about giving the COM-Server informations for people who might know a more specific problem that could be then. I will take a look at the mentioned method – Nico Feb 24 '17 at 10:00
  • I just checked it and the function readFully() is not available to me. I just have read(),read(byte[]),skip,reset,close and read(byte[],int,int)...Eclipse and the doc is telling me it's java.io.InputStream however.. – Nico Feb 24 '17 at 10:11
  • @kleopi: please check before comment [Answer from @Lolo](http://stackoverflow.com/a/25900095/3266248) – mihatel Feb 24 '17 at 10:14
  • Okay I'm sorry i probably messed up there. For further reference however i found this: http://stackoverflow.com/questions/19839172/how-to-read-all-of-inputstream-in-server-socket-java – kleopi Feb 24 '17 at 10:15
  • ObjectInputStream is not possible since I have a plain tcp communication that will be handled in an layer above to use different protocols. This stream adds an header that is not good to handle for later use. Still thank you for the Ideas – Nico Feb 24 '17 at 11:43