Sever code
if(success){
out.write("true".getBytes().length);
out.write("true".getBytes());
out.flush();
}
else{
out.write("false".getBytes().length);
out.write("false".getBytes());
out.flush();
}
Client Code
int size = inputStream.read();
byte[] buf = new byte[size];
inputStream.read(buf);
ns = new String(buf);
Boolean.valueOf(ns);
Although the sever send the result client read it wrong. What is the problem in here? how can i solve it. As example sever send value true but client receive it as false
You need to step thread what you are doing exactly. Obviously the simplest way to sent a boolean is as a single byte like this.
out.write(success ? 1 : 0);
and to read this you would do
boolean success = in.read() != 0;
However, if you need to send a string, I would check what string you are reading and what the correct length is, because there is any number of reasons a binary protocol can fail, e.g. because the previous thing you read/wrote was incorrect.
Server and Client are probably using different charsets.
Use an explicit one (and the same) in both sides.
see http://docs.oracle.com/javase/6/docs/api/java/lang/String.html
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException
and
public String(byte[] bytes,
String charsetName)
throws UnsupportedEncodingException
Related
I'm trying to serialize Object between NIO SocketChannel and blocking IO Socket. Since I can't use Serializable/writeObject on NIO, I thought to write code to serialize object into an ByteArrayOutputStream then send array length followed by array.
Sender function is
public void writeObject(Object obj) throws IOException{
ByteArrayOutputStream serializedObj = new ByteArrayOutputStream();
ObjectOutputStream writer = new ObjectOutputStream(serializedObj);
writer.writeUnshared(obj);
ByteBuffer size = ByteBuffer.allocate(4).putInt(serializedObj.toByteArray().length);
this.getSocket().write(size);
this.getSocket().write(ByteBuffer.wrap(serializedObj.toByteArray()));
}
and receiver is:
public Object readObject(){
try {
//Leggi dimensione totale pacchetto
byte[] dimension = new byte[4];
int byteRead = 0;
while(byteRead < 4) {
byteRead += this.getInputStream().read(dimension, byteRead, 4 - byteRead);
}
int size = ByteBuffer.wrap(dimension).getInt(); /* (*) */
System.out.println(size);
byte[] object = new byte[size];
while(size > 0){
size -= this.getInputStream().read(object);
}
InputStream in = new ByteArrayInputStream(object, 0, object.length);
ObjectInputStream ois = new ObjectInputStream(in);
Object res = ois.readUnshared();
ois.close();
return res;
} catch (IOException | ClassNotFoundException e) {
return null;
}
}
The problem is that size (*) is always equals to -1393754107 when serializedObj.toByteArray().length in my test is 316.
I don't understand why casting not works properly.
this.getSocket().write(size);
this.getSocket().write(ByteBuffer.wrap(serializedObj.toByteArray()));
If the result of getSocket() is a SocketChannel in non-blocking mode, the problem is here. You aren't checking the result of write(). In non-blocking mode it can write less than the number of bytes remaining in the ByteBuffer; indeed it can write zero bytes.
So youu aren't writing all the data you think you're writing, so the other end overruns and reads the next length word as part of the data being written, and reads part of the next data as the next length word, and gets a wrong answer. I'm surprised it didn't barf earlier. In fact it probably did, but your deplorable practice of ignoring IOExceptions masked it. Don't do that. Log them.
So you need to loop until all requested data has been written, and if any write() returns zero you need to select on OP_WRITE until it fires, which adds a considerable complication into your code as you have to return to the select loop while remembering that there is an outstanding ByteBuffer with data remaining to be written. And when you get the OP_WRITE and the writes complete you have to deregister interest in OP_WRITE, as it's only of interest after a write() has returned zero.
NB There is no casting in your code.
The problem was write() returned 0 always. This happens because the buffer wasn't flipped before write().
I am using: Android Studio/Java 1.8 (Client) VS2010/.NET 4.0 (Server)
This Java code is constantly sending invalid data:
long FileSize = 1131666;
byte [] fs = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(FileSize).array();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("FILE".getBytes());
baos.write(fs); //HERE
baos.write(GetHash().getHexStdstring().getBytes());
baos.write(dest_filename.getBytes());
OutputStream out = socket.getOutputStream();
out.write(baos.toByteArray());
out.flush();
This is what I get (viewed with wireshark):
46:49:4c:45: ("FILE")
3f:44:11:00:00:00:00:00: (1131583)
32:37:64:35:36:61:32:34:32:36:31:30:37:36:37:32:30:65:34:38:66:37:34:65:36:61:64:38:34:65:36:30:65:64:33:63:66:64:34:36:32:64:36:62:37:65:62:64:62:32:63:63:62:37:37:64:36:38:37:66:64:64:66:39:
5c:45:75:72:6f:70:65:2e:70:6e:67
And thus my C++ server app receives the value as 1131583, but no matter what value I use as FileSize, I always seem to get a 3f in there somewhere...
Another instance is when the FileSize is 22451663, I get 3f:3f:56:01:00:00:00:00 (or 22429503).
Any thoughts?
Weird thing is, if I translate fs back to a number or a string and Toast the value, just before it's sent, it says its correct.
6:49:4c:45: ("FILE")
00:00:00:00:00:11:44:3f: (1131583)
Cannot reproduce, and 00:00:00:00:00:11:44:3f: is not a little-endian representation of 1131583. It is a big-endian representation of 1131583. As a little-endian number it is a rather large number: 4347598471168.
What this code actually produces on the wire, as printed by
ByteArrayOutputStream baos = new ByteArrayOutputStream()
{
public void write(byte[] bytes) throws IOException
{
for (byte b : bytes)
{
System.out.print(Integer.toHexString(b & 0xff)+":");
}
System.out.println();
super.write(bytes);
}
};
is:
46:49:4c:45:
92:44:11:0:0:0:0:0:
// etc.
There is no problem with this code.
So, the ISO-8859-1 character for 0x3f is ?, and it seems that because I was sending my constructed ByteArayOutputStream to my Send(String string) function, it was changing a lot of bytes to 0x3f, like 0x92 which has no ISO-8859-1 character.
I changed my code to like so:
// in main code
Bytestring message = new Bytestring(baos.toByteArray());
Send(message);
// send function
public void Send(Bytestring string) {
OutputStream out = socket.getOutputStream();
// other code for writing header
out.write(string.getBytes());
out.flush();
}
Bytestring being a string class I created based on a byte array, instead of a String which is based on a (2-byte) char array.
I need to send a text message to server over Java socket and then to send a byte array and then a string etc...
What I've developed until now is working but the client manages to read only the first string that has been sent.
From the server side: I send byte array using BufferedOutputStream, and PrintWriter to send string.
The problem is that the client and the server are not synchronized, I mean the server send string then byte array then string without waiting for the client to consume each needed byte.
I mean the scenario is NOT like this:
Server Client
Send String read String
Send byte read byte
But it is like this:
Server Client
Send String
Send byte
Send String
Send byte
read String
read byte
read String
read byte
Something that could be useful is that I know exactly the size of each string and each byte array to be read.
Here is the methods used to send string and byte array respectively:
// Send String to Client
// --------------------------------------------------------------------
public void sendStringToClient (
String response,
PrintWriter output) {
try {
output.print(response);
output.flush();
} catch(Exception e) {
e.printStackTrace();
}
System.out.println("send Seeder String : " + response);
}
// Send Byte to Client
// --------------------------------------------------------------------
public void sendByteToClient (
byte[] response,
BufferedOutputStream output) {
try {
output.write(response, 0, response.length);
//System.out.println("send : " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
Here is the methods used to read string and byte array respectively:
public byte[] readInByte(int size) {
byte[] command = new byte[size];
try {
this.inByte.read(command);
} catch (IOException e) {
e.printStackTrace();
}
return command;
}
public String readInString(int size) {
char[] c = new char[size];
try{
this.inString.read(c, 0, size);
} catch (IOException e) {
e.printStackTrace();
}
return String.valueOf(c);
}
Something that could be useful is that i know exactly the size of each string to be read and each byte array to be read.
Exactly. That's very common. Basically you length-prefix each message - and you might want to provide more header information than that (is it a string or a byte array message, for example).
You could represent the message length (always in bytes) either as a fixed number of bytes (e.g. 4, assuming you never need more than 4GB messages) or use a 7-bit encoded integer (where you send 7 bits of the length in each byte, and the top bit just indicates whether this is the last byte of the length or not).
Once you've got message lengths, you're basically set - you've effectively divided the stream of data into self-describing blocks. Job done.
(As an aside, I'd avoid using PrintWriter due to its exception-swallowing nature. You won't actually need the writer once you're doing this though, as you'll probably want to convert each String into a byte array anyway, to count its length in bytes before you send it. Remember to specify the encoding!)
I'd be really tempted to convert the data to JSON format and pipe it over http. You get a ton of benefits including ready made http servers and clients for just about every platform on earth along with the JSON interop not to mention all the built in error handling and recovery processing.
The drawbacks would be the additional overhead of http and the JSON encoding. You didn't mention if this was a UDP or TCP socket so that could be an additional drawback if you were trying to go connectionless.
I would like to get data from InputStream() as a String eg. Hi, Start, Stop, etc.
My Code fragment is
byte[] buffer = new byte[1024];
inputStream.read(buffer);
My data is Command Sent from Bluetooth.
The above code fragment only get (eg. 2 if I sent Hi, 5 if sent Start), I would like to get back Normal String as the same from the Sender Side.
I found only converting way from String to InputStream.
any suggestion , I would like to appreciate!
finally, i can solve this!
inputStream.read(buffer); only return the int num of how many bytes is in the buffer and the data from the socket is stored in buffer. So, from the buffer you can make String
eg. String result = new String (buffer);
The simplest way is via the Apache common-io library:
String input = IOUtils.toString(inputStream);
See the javadoc for this method for more.
NOW here is the coding for j2me mobile for sending the string:
String s="hai";
try{
String url = "btspp://001F81000250:1;authenticate=false;encrypt=false;master=false";
StreamConnection stream = null;
InputStream in;
OutputStream out;
stream = (StreamConnection) Connector.open(url);
out=stream.openOutputStream();
String s=tf.getString();
byte size=(byte) s.length();
out.write(size);
out.write(s.getBytes());
out.flush();
out.close();
stream.close();
}
catch(Exception e){
}
NOW the coding for j2se for receiving the String :
StreamConnectionNotifier notifier=null;
try{
String url = "btspp://localhost:"+new UUID("1101", true).toString()+";name=PCServerCOMM;authenticate=false";
System.out.println(LocalDevice.getLocalDevice().getBluetoothAddress()+"\nCreate server by uri: " + url);
notifier= (StreamConnectionNotifier) Connector.open(url);
while(true){
System.out.println("waiting....");
StreamConnection con = notifier.acceptAndOpen();
System.out.println("Got connection..");
InputStream is=con.openInputStream();
//byte b[]=new byte[40];
/*
while(is.available()>0){
System.out.print((char)is.read());
}*/
//is.read(b, 0, 40);
int size=is.read();
byte b[]=new byte[size];
is.read(b, 0, size);
File f=new File("d://test.xml");
FileOutputStream fo=new FileOutputStream(f);
fo.write(b,0,b.length);
fo.close();
con.close();
System.out.println(new String (b));
}
//printing(f);
} catch(Exception e){
JOptionPane.showConfirmDialog(new JFrame(), e.getMessage());
}
I tried this coding for data transfer but it is not a successful one because when the string which we sent is too long then there is problem in receiving side. How can I solve this?
Is there any other way to transfer the data in rms to j2se, if so please help me.... please make your reply quick...
The way you are writing and reading here, only strings up to 255 characters in length, which additionally only take the same number of bytes in your default encoding, are written right.
On the writing side:
The statement byte size=(byte) s.length(); converts the length of the string in a byte, thus only takes the lower 8 bits of the length. So, only lengths up to 255 are written right.
Then you are converting the String to a byte array with s.getBytes() - this array could be longer (in bytes) than the original string in characters. This conversion uses the default encoding of your sending device.
On the reading side:
The statement int size=is.read(); reads the length written before, then you are creating a byte array.
is.read(b, 0, size); reads some bytes into this array - it does not necessarily fills the complete array.
Then you are converting your byte array (which may not even be filled completely) to a string, using the default encoding of the receiving device.
So, we have:
All strings longer than 255 characters are written wrongly.
If sending and receiving side are using different encodings, you may get a wrong output.
If the sending side uses an encoding like UTF-8 where some characters take more than one byte, the string is cut off at the end (if such characters occur).
How to solve this:
If you can use a DataInputStream and DataOutputStream on both sides (I don't know anything about J2ME), use them there, with their readUTF and writeUTF methods. They solve all your problems (if your strings take at most 65535 bytes in the modified UTF-8 encoding used here).
If not:
make a decision on how long the strings can be, and encode your length with the right number of bytes. 4 bytes are enough for every Java String.
measure the length after converting to a byte[], not before.
use a loop for reading into the array, to be sure to capture the whole string.
for the getBytes() and new String(...), use the variants which take an explicit encoding name and give them the same encoding (I recommend "UTF-8").