Im trying to build a basic proxy 4 server, and I have to parse a packet and extract its informations that looks like this:
1 byte (version)
1 byte (command)
2 byte (port)
4 byte (ip)
X byte (userID, builds a string by looping until '\0' is found)
Here's my code so far:
InputStream reader = socket.getInputStream();
byte[] ver = new byte[1];
byte[] cmd = new byte[1];
byte[] port = new byte[2];
byte[] ip = new byte[4];
reader.read(ver, 0, 1); //should be: 4
reader.read(cmd, 1, 1); //should be: 1
reader.read(port, 2, 2); //should be: 00, 80
reader.read(ip, 4, 4); //should be: 217, 70, 182, 162
Here's the response I get from my code: [4, 1, 0, 80, -39, 70, -74, -94]
For some reason the IP part I get is always wrong, I really don't know why. My second issue would be: Is there an easy and clean way to get the last userID string part, without having to build a messy loop that could end up hanging for ever, if the \0 byte was not found?
Throw it all away and use the methods of DataInputStream. They will give you ints, shorts, longs, and fully-read byte arrays, and take care of network byte ordering for you as well.
The first issue which you received is all because of byte-overflow and hence,turning to negative numbers as byte ranges from -128 to 127 in Java.
Check this question which I asked on this forum to know about the magic(issues) of byte[]...
Seriously,if this is your approach for last-field,(ip)---I am sure you're not going to get correct answer using direct reforms on byte. The possible solution seems to use other approach like storing in temporary int[], like
int[] ip = new int[4];
byte[] temp = new byte[4];
reader.read(temp, 4, 4); //should be: 217, 70, 182, 162
for(int i=0;i<temp.length;i++)
{
if(temp[i]<0)
ip[i]=(int)(256+temp[i]); // careful here
else
ip[i]=(int)temp[i];
}
And,for the second issue,I think that better solution is get length of String-part using String.length().
int len = userID.length(); // assume user-id would be String type
userid = new byte[len]; // notice the difference between userid and userID
reader.read(userid,0,len);
// I am confused as to how are you reading input from user,
// if you clarify further,I'll update my answer...
Related
I have a byte array of 151 bytes which is typically a record, The record needs to inserted in to a oracle database. In 151 byte of array range from 0 to 1 is a record id , 2 to 3 is an reference id , 4 to 9 is a date value. The following data in an byte array is a date value. i want to convert it to string
byte[] b= {48,48,49,48,48,52}; // when converted to string it becomes 10042.
new String(b); // current approach
is there any way to efficiently to convert byte array of some range (Arrays.copyOfRange(b,0,5)) to string .
new String(b, 0 ,5);
See the API doc for more information.
Use the String(bytes[] bytes, int offset, int length) constructor: http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#String(byte[], int, int)
new String(b, 0, 5);
If you need to create a string for each region in the record, I would suggest a substring approach:
byte[] wholeRecord = {0,1,2 .. all record goes here .. 151}
String wholeString = new String(wholeRecord);
String id = wholeString.substring(0,1);
String refId = wholeString.substring(1,3);
...
The actual offsets may be different depending on string encoding.
The advantage of this approach is that the byte array is only copied once. Subsequent calls to substring() will not create copies, but will simply reference the first copy with offsets. So you can save some memory and array copying time.
None of the answers here consider that you might not be using ASCII. When converting bytes to a string, you should always consider the charset.
new String(bytes, offset, length, charset);
and here fantastic way (not efficient) :)
byte[] b = { 48, 48, 49, 48, 48, 52 };
ByteArrayInputStream bais = new ByteArrayInputStream(b);
BufferedReader buf = new BufferedReader(new InputStreamReader(bais));
String s = buf.readLine();
System.out.println(s);
I've been writing a simple file transfer program which opens a TCP connection to a server, negotiates the terms of the file transfer (over TCP) and streams the file from the client to the server. The problem is large files almost always corrupt. I logged the socket InputStream and OutputStream and found that while the data matches at first, after several kilobytes an interesting desync occurs.
At a certain point the receiving socket starts reading 0 while the sending socket continues sending the file data.
Example:
Server: ..., -75, 82, 34, -109, 50, -51, 52, 9, -14, -70,...
Client: ..., -75, 82, 34, -109, 50, 0, 0, 0, 0, 0,...
However After a bit it recovers
..., 0, 0, 0, 0, 0, -51, 52, 9, -14, -70,...
You'll note it resumes where it left off. The only problem is now I have a bunch of zeros in my file and the end of the stream will not be recorded into the file (as the file length is sent ahead of time).
NOTE: this only seems to happen some of the time (more often than not)
The streaming code itself:
Sender:
<header stuff, I checked it works fine>
long dataLeft = 0;
while(dataLeft < packet.payloadSize){
packet.remaining = packet.payloadSize-dataLeft;
byte[] temp = new byte[packet.remaining<8192?(int)packet.remaining:8192];
packet.inStream.read(temp);
stream.write(temp);
dataLeft+=temp.length;
}
stream.flush();
<Rest of the code>
Receiver:
public boolean streamPayload(OutputStream out) throws IOException{
long dataLeft = 0;
while(dataLeft < payloadSize){
remaining = payloadSize-dataLeft;
byte[] temp = new byte[remaining<8192?(int)remaining:8192];
inStream.read(temp);
out.write(temp);
dataLeft+=temp.length;
}
return true;
}
long dataLeft acts as the index btw.
Does anyone know why this might be happening and how I can fix it/compensate for the issue? I know I can't tell if a zero is intended so I can't just listen for the issue by watching the output.
I don't know if this will solve your problem but one thing you are doing wrong is ignoring the amount of data transferred.
InputStream in = //from somewhere
OutputStream out = //to somewhere
byte[] buffer = new byte[8192];
int read = -1;
while ((read = in.read(buffer)) > -1) {
out.write(buffer, 0, read);
}
out.close();
int.close();
You could be reading data without receiving any and then writing 8192 byte buffer that is empty because you didn't check if anything came through.
I am trying to send through Websocket binaryType protocol some raw data from Java Servlet to JavaScript
I read all about Byte Buffer, Typed Arrays and Data View on JavaScript but still I think I am missing the picture
My question is how do I convert an array of 8 bytes to a JavaScript Number?
I have the following byte array that should represent this double value
-1.4960627518157586E23
0 = -60
1 = -65
2 = -82
3 = 44
4 = 36
5 = 69
6 = -96
7 = 64
Can anybody help me in serializing byte data from Java to JavaScript types please?
Much appreciated.
Reading in Javascript
Reading binary data in Javascript takes some effort, but someone conveniently made a snippet of code which helps with that: http://jsfromhell.com/classes/binary-parser
We can use it like so:
var parser = BinaryParser(true);
var outputVal = parser.toDouble([-60, -65, -82, 44, 36, 69, -96, 64]);
Reading in Java
In case you receive the data in java, you can use java.io.DataInputStream to read primitive values from a stream, like so:
byte[] dataArray = new byte[] {-60, -65, -82, 44, 36, 69, -96, 64};
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(dataArray));
double val = stream.readDouble();
out.println(val); // -1.4960627518157586E23
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.)
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