I'm developing an URCap to a camera installed in an UR Robot and I need to write to and read the response from the camera.
The camera is equipped with an object detection algorithm and the way it works is: we send a String "Run.LocateAll" to it and it returns us the coordinates of the detected objects as "x,y,z,rx,ry,rz" in a string format as well. I am able to send the locate command using writeByte() method (I tried to use writeUTF(), but it strangely sends "%Run.LocateAll" with a % in the beginning of the string, so it doesn't work) and I know that the command is working cause the camera GUI show me the located object.
The problem is the reading, because when I use the readUTF() method the robot program freezes. I already tried other methods like readLine() (it freezes as well), but with no success. I'm gonna put the screenshots of my code and the robot program for you to see.
private static void socketCommunication(ScriptWriter writer, String ip, int port) {
try{
Socket s=new Socket(ip,port);
DataOutputStream dout = new DataOutputStream(s.getOutputStream());
dout.writeBytes("Run.LocateAll,3");
DataInputStream din = new DataInputStream(s.getInputStream());
System.out.println(din.readUTF());
din.close();
dout.flush();
dout.close();
s.close();
}
catch(Exception e){System.out.println(e);}
}
I expected that my program could read from the socket and return me the string "(x,y,z,rx,ry,rz)" of the detected objects
A DataInputStream
and DataOutputStream
uses a specific format for serializing data. If the other side doesn't use the same format, they'll get garbage (or at least, strings that are prefixed by 2 bytes of garbage) when reading, and you can block (or consume too much data) when reading.
Specifically, writeUTF()
writes a 2-byte (i.e. writeShort(int)
) length prefixed byte array, and uses a "modified" UTF-8 for converting strings to bytes. That is probably why the other side gets a %
(or more likely, \000%
), though that would mean the string was 37 characters, and not 15 characters like "Run.LocateAll,3"
as that results in a prefix of (unprintable) \000\017
.
In the same vein, readUTF()
interprets the first 2 bytes (i.e. readUnsignedShort()
) as a length, and will then read that number of bytes and convert those bytes to string with the same modified UTF-8 encoding. This means that if the other side didn't send something written with writeUTF()
(or equivalent implementation), it might actually try to read too many bytes and block indefinitely if the peer sent a lot less bytes (which would explain the freezing you mention).
For example, if the peer sends the string "Hello"
as bytes 0x48, 0x65, 0x6C, 0x6C, 0x6F (i.e. not length-prefixed), then the He
is interpreted as a length of 18533, meaning that the DataInputStream
will try to read 18533 bytes, while the peer has only 3 bytes remaining (the llo
part of Hello
). The input stream will then block waiting for the remaining 18530 bytes.
In short, the behaviour you describe, suggests that it doesn't use the data serialization format of DataInputStream
and DataOutputStream
, and possibly expects plain strings (e.g. written with an OutputStreamWriter
and read with an InputStreamReader
, though that is hard to do correctly if you don't know how many bytes to expect, unless messages have a clear boundary!).
You'll need to find the documentation of the actual protocol of this camera, and correctly implement it. DataInputStream
and DataOutputStream
at least are (or seem to be) the wrong tools for this job.
As an aside, flushing your output stream after trying to read data from your peer doesn't make much sense. You should flush before trying to read data from your peer, to prevent cases where the peer is waiting for data that is still buffered on your side.