Decode "send" message from WebSocket with Java - java

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

Related

Java Server & C# Client freezing

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

Why is extra data being written to my output stream and how can I stop this?

I am trying to build a simple connection between my Java server (it sends information) and my C client (it receives info).
I want to send one single integer representing the size of an array and then a byte array itself. My java code looks like this
Socket sc = new Socket("52.187.54.73", 19000);
while(true)
{
System.out.println("Socket open");
DataOutputStream outToClient = new DataOutputStream(sc.getOutputStream());
Random rand = new Random();
int rlen = rand.nextInt(10)%10 + 1;
byte[] a = new byte[rlen];
System.out.println("Size of the array is " + rlen);
for(int i = 0; i < rlen; i++)
a[i] = (byte)rand.nextInt(100);
outToClient.write(rlen);
outToClient.write(a,0,rlen);
//close socket
sc.close();
System.out.println("Done!");
//Break once done
break;
}
and my C code looks like this
ptr1 = (void *)calloc(1, sizeof(int));
while(1){
sin_size = sizeof(client_addr);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
printf("\n Got a connection from (%s ,%d)",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
bytes_received = recv(connected,ptr1,10,0);
if(bytes_received<0){
printf("Something went wrong %s\n", strerror(errno));
}
printf("Bytes received: %d \n", bytes_received);
for(int i =0; i<bytes_received; i++){
unsigned char a = *(unsigned char *)(ptr1 + i*sizeof(unsigned char));
printf("Inc: %d", a);
}
Assuming that the above block of code works and I am able to get the value of rlen the code for processing the array is as follows:
ptr2 = calloc(rlen, sizeof(unsigned char));
bytes_received = recv(connected, ptr2, 1,0);// incoming, 0);
printf("bytes received: %d\n", bytes_received);
for(int i = 0; i < rlen; i++){
printf(" i = %d, val = %d\n ", i,*(unsigned char *)(ptr2 + i*sizeof(unsigned char)));
}
Now the Java server sends a number between 1 and 10. I was earlier trying to read the number sent using int incoming = *(int *)ptr1; but for some reason, occasionally I would get huge values like 51020210.
To check why this was happening and debug I wrote the code block:
for(int i =0; i<bytes_received; i++){
unsigned char a = *(unsigned char *)(ptr1 + i*sizeof(unsigned char));
printf("Inc: %d", a);
}
It turns out that sometimes, the integer being sent becomes very large.
Why is this happening? On the server side printing out rlen shows me the right value, but non-deterministically I get random really large values at the client side.
Note that whatever number I receive on the client side has the first number as the value of rlen.
So for example if rlen is 6, then the random really large value is something like 689932423
Later the values of rlen will become very large in the order of 1000s so I need to solve this problem and cannot simply take the first byte of whatever I get on the client side.
The problem with my code was in this line as rightly pointed out in the comments
bytes_received = recv(connected,ptr1,10,0);
I was mistakenly trying to read more than 4 bytes which is the exact number needed to convert to an integer value.
Alternatively, to read 4 and only 4 bytes, this could be written as
bytes_received = recv(connected, ptr1, 4, 0|MSG_WAITALL);
On the java side, again as pointed out in the comments, the function write(int) only sends 1 byte.
To send multiple bytes first the integer must be converted into a 4 byte array, and then each byte in the array must be sent like this
outToClient.write(rlen_array, 0, 4);

Converting pointer to string and send as char array not working properly

I have a problem with sending directory names over socket from my C++ client, to my Java server.
Sending ordinary messages like "hello world", works great , but the following doesn't and I can not figure out what the problem is:
char const * files = ffd.cFileName; // get directory name
string str(files, 0, strlen(files)); // convert pointer to string, right?
char mess[str.size()];
strcpy(mess, str.c_str()); // make char array :)
cout << "Send file: " << mess << " with strlen: " << strlen(mess) << " and sizeof: " << sizeof(mess) << endl;
int sent = 0;
if ((sent = send(connectSocket, mess, sizeof(mess), 0)) == SOCKET_ERROR)
{
closesocket(connectSocket);
WSACleanup();
connectToServer();
}
The java server just receives the directory names like this:
wam
p
Win
dow
s
Win
dow
s.o
ld
wxW
idg
ets
I can not understand what I'm missing because I have tried every possible way to do this and the C++ client prints like:
"Send file: windows with strlen: 7 and sizeof: 7"
I do not think that the java server is the problem since I can receive normal strings and messages perfectly, but anyway here is the JAVA code:
is = socket.getInputStream();
byteArray = new byteArray[1024];
while (true) {
c = is.read(byteArray, 0, byteArray.length);
String recv = new String(byteArray, 0, c);
System.out.println(recv);
if (recv.equals("<EOF>")){
break;
}
list.add(recv);
}
If you request something else or anything just leave a comment and I will fix it.
Question: are you sending via TCP or UDP? I'm guessing TCP, and if that is the case, you need to treat the socket as more of a stream. That stream may get broken up into a bunch of packets - you don't really control that. What I might do is to prefix the string length of each directory (ex, 3foo, 4barz, etc), read from the socket and determine what constitutes as a logical block or string, and then assemble / print the strings based on that. If you go with that route, you need to track how much you read each time until you think you are done.
I solved it, Just added byteArray = new byte[1024]; and now it works:
while (true) {
byteArray = new byte[1024]; // I ADDED THIS AND NOW THE JAVA SERVER RECEIVES IT CORRECTLY!
c = is.read(byteArray, 0, byteArray.length);
recv = new String(byteArray, 0, c);
System.out.println(recv);
if (recv.equals("<EOF>")){
break;
}
list.add(recv);
}

Integer to byte and byte to integer convertion - java

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.)

How to send C char array to Java client over a socket

I'm writing a server program in c, and the client is on android platform which uses java language.Now I have a trouble to send char array from the server to the client,which means the client can get the data but can not decode it.I think it maybe because of the problem of data types or encoding differences.Can anyone give me some ideas,Thanks a lot!
Here is my code of server side:
char buf[MAXSIZE];
memset(buf, 0, MAXSIZE);
int n_write;
strcpy(buf, "0008200050005001");
n_write = Write(confd, buf, strlen(buf));
if (n_write <= 0)
{
fputs("Write error in send_matrix_and_position\n", stderr);
close(confd);
return -1;
}
And here is Java code:
mSocket = new Socket(HOST, PORT);
mIn = mSocket.getInputStream();
mOut = mSocket.getOutputStream();
byte[] lengthByte = new byte[4];
mIn.read(lengthByte);
for(byte b : lengthByte)
{
System.out.println(b + "");
}
You are sending 16 characters, but you read only four. Aren't you getting the data
48
48
48
56? These are the codes of the first four characters sent.
Try checking what values you get at the client when you read the char array, you might probably be doing br.readline(); see if this prints the characters??
You need to debug and check, then you might come up with some way.

Categories

Resources