I'm developing an app based on Samsung Chord SDK. I need to send the video's current position in the sendDataToAll(), which accepts data in byte[][]. My problem is that when I try to send the current position (which is an int) type-casted into byte, I'm getting negative value (in byte) as returned. And when I try to convert the negative value in to int in the OnDataRecived(), it's still the same negative value. How do I solve this issue?
Sending code:
//for sending the message
int currPos = mVideoView.getCurrentPosition();
logView.append("Duration sent= " + currPos);
//Integer resume = -3;
Byte msgByte = new Byte("-3");
byte [] [] pay = new byte [1] [2];
pay[0] [0] = msgByte;
Byte msgByte2 = new Byte((byte) currPos);
logView.append("Duration sent= " + msgByte2);
pay[0] [1] = msgByte2;
mChordchannel.sendDataToAll("Integer", pay);
// im sending -3 so that im checking that the user pressed the resume .
Receiving code:
//on receiving
else if(intRec == -3) {
Byte pos = rec[0] [1];
int posn;
posn = pos.intValue();
logView.append("Duration received= " + posn);
mVideoView.seekTo(posn);
mVideoView.start();
}
I don't know anything about the Samsung Chord SDK, but you can't fit (most) ints in a byte. An int is 4 bytes wide.
To create a payload compatible with your current code, that sends all 4 bytes:
byte[][] payload = { {
-3,
(byte)(currPos >> 24),
(byte)(currPos >> 16),
(byte)(currPos >> 8),
(byte)(currPos >> 0),
} };
mChordchannel.sendDataToAll("Integer", payload);
To receive:
int position = new java.math.BigInteger(
Arrays.copyOfRange(rec[0], 1, 5)).intValue();
P.S. This is not pretty code! It is tolerable for basic ints, but if you later find you need to transmit more complicated data structures you will need a better way. Some ideas, in increasing order of sophistication:
Use data streams (wrap a DataOutputStream around a ByteArrayOutputStream; write values; when done writing, close the DataOutputStream and call toByteArray() on the ByteArrayOutputStream to get the payload).
Use serialization (wrap an ObjectOutputStream around a ByteArrayOutputStream; write values and/or objects; finish as above).
Use a JSON-encoder or XML-encoder. (E.g., encode the data as a String, then call getBytes("UTF-8") on the String and send that.)
Related
I am trying to interface a Nextion HMI Serial Screen to Android Things, specifically the PICO-PI-IMX6UL
I am using the sample-uartloopback template as a starting place.
What I need to do is send the following payload over serial (UART3) in a certain format and in ASCII
page 1
The instruction is ended with three bytes "0xff 0xff 0xff"
All the instructions and parameters are in ASCII
All the instructions are in lowercase letters
mLoopbackDevice.write(buffer, buffer.length);
Where buffer is the payload with the three terminating bytes.
The thing is the screen wants in in ASCII but I can only send in the bytearray...
I have tried multiple ways and I cant seem to get it to work.
What would be the proper way to format a string of "page 1" and then add the terminating bytes?
I have it working in a node app but java is blowing my mind right now...
I have tried:
String strCommand = "page 1";
byte b = (byte)0xFF;
byte[] endCommand = {b,b,b};
byte[] cmd = strCommand.getBytes();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(cmd);
outputStream.write(endCommand);
byte[] payload = outputStream.toByteArray();
Screen.write(payload, payload.length);
but that does not work.
I can read data (nothing useful at the moment) so I can confirm the communication is fine and It works in my Node app, but I need to port it to Android Things...
Can anyone point me in the right direction?
EDIT: This returns the correct format for me in JS
function hex(str) {
var arr = [];
for (var i = 0, l = str.length; i < l; i ++) {
var ascii = str.charCodeAt(i);
arr.push(ascii);
}
arr.push(255);
arr.push(255);
arr.push(255);
return new Buffer(arr);
}
I have got a Java Server and a C# Client. And I'm really certain something goes wrong with the outputstreamer on the client or inputstream on the server.
byte[] arr = IOUtils.toByteArray(is,14);
PrintWriter out = new PrintWriter(os, true);
out.print("Received "+ new String(arr,"UTF-8"));
out.flush();
out.close();
"is" in this case is the Input Stream Variable. Coming from Socket.getInputStream().
Removing the length of the stream (14 in this case) makes the system time-out. The client does not get any respons except: "Read Failure"
The client side consists of a C# program
byte[] start = getIdentifier();
byte[] end = Encoding.UTF8.GetBytes(toSend);
byte[] arr = start.Concat(end).ToArray();
//Arr variable is a couple of strings smashed together and transformed into a byte[]
networkStream.Write(arr, 0, arr.Length);
networkStream.Flush();
StreamReader streamReader = new StreamReader(networkStream);
result = streamReader.ReadToEnd();
I actually tried writing to the Server with a BinaryWriter too, but that didn't work either. If I know what the length of the data is that will be send, I can fix the problem. But I do not know how to send the length of the stream to the server.
I've tried using Available() to see how much there was to read, but for some reason that sometimes was 0. As if the data wasn't been sent by the client yet.
Any ideas of how to fix the freezing?
EDIT:
I think I understand how the streaming works now.
At first I did this on the client side:
var length = BitConverter.GetBytes(arr.Length);
Array.Reverse(length);
Then on the server side I put this piece of code:
/* Get Input Data Length */
byte[] arr = IOUtils.toByteArray(is, 4);
int length = (arr[0] << 24) & 0xff000000 |
(arr[1] << 16) & 0x00ff0000 |
(arr[2] << 8) & 0x0000ff00 |
(arr[3] << 0) & 0x000000ff;
/* Get Input Data */
arr = IOUtils.toByteArray(is, length);
#Andreas your mention of the big-endian byte order made it clear how to send the length to the server
I have a Multi threaded TCP socket listener program. I do a blocked read for data of a particular no of bytes(128 bytes and 4xmultiples),so my packet sizes are 128 bytes,256 bytes,384 bytes and 512 bytes.
I am having problem because sometimes data is getting messed in the socket. For eg:
Supposed to read:
<header><data payload(padded with zeros to compensate size)><footer>
ex-- ABCDddddddddd0000000000WXYZ
What i read sometimes:
ex-- ABCDdd00000000000000000dddddd00
and then the next packet looks like
00000WXYZABCDddddd00000000000000000
so i close the socket and we have defined the protocol to send back 2 or 3 old packets to avoid the loss.
my questions are
1. why does the data get scrambled/messed?
2. can it be avoided by any means?
here is my code for read data.
in = new DataInputStream(conn.getInputStream());
outStream = conn.getOutputStream();
while (m_bRunThread) {
// read incoming stream
in.readFully(rec_data_in_byte, 0, 128); //blocks until 128 bytes are read from the socket
{
//converting the read byte array into string
//finding out the size from a particular position,helps determine if any further reads are required or not.
//if the size is a multiple of 128 and the size is a multiple higher than 1 then more reads are required.
if ((Integer.parseInt(SIZE) % 128 == 0) && ((SIZE / 128) > 1)) {
for(int z = 1;z < lenSIZE;z++) {
in.readFully(rec_data_in_byte1, 0, 128);//changed from in.read(rec_data_in_byte1, 0, 128); as per suggestions
}
//extracting the data,validating and processing it
}
}
}
UPDATE:
Implemented Peters fix but the problem still persists. data is getting scrambled.
adding a few lines of extra code where the byte array is converted into a string.
byte[] REC_data=new byte[1024];
System.arraycopy(rec_data_in_byte1, 0, REC_data, 128*z, 128);
rec_data_string=MyClass2.getData(REC_data,0,Integer.parseInt(SIZE)-1,Integer.parseInt(SIZE));
the getdata() method is below:
String msg = "";//the return String
int count = 1;
for (int i = 0; i < datasize; i++) {
if (i >= startindex) {
if (count <= lengthofpacket) {
msg += String.valueOf((char) (bytedata[i]));
count++;
}
}
}
return msg;
can any of this be the reason for the scramble?
P.S-the scramble is happening the same way as it was happening before.
When you do
int lengthActuallyRead = in.read(rec_data_in_byte1, 0, 128);
You need to check the length read. Otherwise it might read 1 byte, or anything up to 128 in this case. Note, any bytes after what was actually read are untouched so they might be 0 or they could be garbage left from a previous message.
If you expect 128 bytes you can use readFully as you did previously
in.readFully(rec_data_in_byte, 0, 128);
Note: If the amount remaining is less than 128 you might want to do this.
int remaining = size - sizeReadSoFar;
int length = in.read(rec_data_in_byte1, 0, remaining);
This prevents you reading part of the next message while you are still reading the old one.
In my application, clients sends file to the server in this format,
4 bytes of file length + actual file content
So the server reads the first 4 bytes to get the length of message and then it reads upto that message length.
The server code will be like this,
ByteArrayOutputStream lengthBuf = new ByteArrayOutputStream(4);
byte[] output = new byte[4];
//Reading first 4 bytes from InputStream
int readLength = inputStream.read(output);
lengthBuf.write(outpu, 0, readLength);
//Converting to integer
int length = ByteBuffer.wrap(lengthBuf.toByteArray()).getInt();
It works fine for valid cases. But in case if the client fails to append the length in the first 4 bytes, then this length got some junk value (1481988969). How to validate that the first 4 bytes of data is a valid integer ?
As long as you are fixed to 4 bytes and all values of the integer can be valid, there is no way.
However if you can more bytes. You can add a fifth byte and e.g. use CRC or other error-detecting codes to check if the value has correctly been transmitted.
Another option would be if you actually do not need all bits of the four transmitted bytes, that you use some bits of them.
Both actually needs access to the Server-Implementation of the Socket. If you don't have this access, it will not be possible to check if the integer is correct. You only can exclude file sizes which you know that they never occur. E.g.:
if (integer < MAX_FILE_SIZE and integer > 0) valid();
// or integer >= 0 if empty files are allowed.
else invalid();
I would do it this way.
DataInputStream dis = new DataInputStream(inputStream);
int len = dis.readInt(); // read exactly 4 bytes
byte[] bytes = new byte[len];
dis.readFully(bytes);
When you do you first read, you could be getting less than 4 bytes. When you read the actual data, you might have to read many times to get it all. read(byte[]) can return as soon as it get 1 or more bytes.
Why don;t you initalize it with at least size four then , when the client fails to append the size >
if(length==null) {
size = 4 ;
}
ByteArrayOutputStream lengthBuf = new ByteArrayOutputStream(size);
int length = ByteBuffer.wrap(lengthBuf.toByteArray()).getInt();
I'm trying to write my own WebSocket Server.
I know that there are some frameworks for this but i would like to learn, so I do it on my own :)
My JavaScript client reacts currently with onOpen, so I think the handshake is valid and
the connection is established.
Now the problem:
My Java server uses a selector thread for reading on an Channel.
If I do *.send("test message") on the WebSocket object at my client, my server can't decode the byte array.
I found no information about the used encode/decode technology, so I tried many versions to decode.
for example:
new String(Base64.decodeBase64(buffer.array()))
or
Charset set = Charset.forName("UTF-8");
new String(Base64.decodeBase64(set.decode(buffer).toString()))
The message is completely read from the Channel into an ByteBuffer, so I don't think this is the problem.
Can anyone help me?
okay this Post helps me to send data to the Client. This works fine :)
But I don't understand how to decode the data received from the Client :(
At the Client i send only one Letter
socket.send("x");
The Server receives 7 byte ???
ByteBuffer buffer = ByteBuffer.allocate(8192);
int read = client.getInputStream().read(buffer2.array());
System.out.println("read: " + read);
// read: 7
for (int i = 0; i < read; i++) {
int j = buffer.get(i) & 0xff;
System.out.println("i: " + i + " => " + j + "=>" + new BigInteger(j + "").toString(2));
}
//i: 0 => 129=>10000001
//i: 1 => 129=>10000001
//i: 2 => 195=>11000011
//i: 3 => 235=>11101011
//i: 4 => 4=>100
//i: 5 => 96=>1100000
//i: 6 => 187=>10111011
If i do this
secondByte AND 0111 1111
the result of (i: 1) is "1" i think this means that there are only one byte data. Then why read is 7 ???
As for your second issue - the data from client to server is always masked as I also explained at the link above. Masks take 4 bytes.
So, the length of the actual data is indeed 1. Only the last 7 bits of the second byte say something about the length - the first bit doesn't, so just discard that one to get 000 0001 which is 1.
The bytes are categorised as follows in this case:
0, 1 are meta bytes
3, 4, 5, 6 are masks
7 is the data
To get the data, calculate data XOR masks[data_index MOD 4], i.e. 187 XOR 195 in this case, which is 120 - the character code for x.
private String decodeMessage(){
try {
byte[] data = new byte[1024];
int size = in.read(data);
if (size == -1) return null;
byte[] decoded = new byte[size-6];
byte[] key = new byte[]{ data[2], data[3], data[4], data[5] };
for (int i = 0; i < size-6; i++) {
decoded[i] = (byte) (data[i+6] ^ key[i & 0x3]);
}
return new String(decoded, "UTF-8");
}catch (IOException ex){
ex.printStackTrace();
}
return "ping";
}
This code is probably bad, but it works for me