I have a thread reading data from a bluetooth stream that sends the data to a handler on the main UIThread as it comes in (based on the Bluetooth Chat Sample).
I've discovered a threading problem that pops up quite frequently. First, some code for reference.
BluetoothService.java (Just the part that reads the incomming data stream. It has been set up correctly before this code runs).
public void run() {
DebugLog.i("BluetoothService", "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
DebugLog.d("BluetoothService", new String(buffer, 0, bytes));
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
DebugLog.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
Handler defined in my main activity (partial):
// The Handler that gets information back from the BluetoothService
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BluetoothService.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
DebugLog.d("BluetoothHandler", readMessage);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
}
}
};
My problem comes when a small, continuous stream of data comes into the mmInStream. For example, 'abcd'. If 'abcd' is read all at once, this code functions normally and the log reads:
BluetoothService: BEGIN mConnectedThread
BluetoothService: abcd
BluetoothHandler: abcd
But if that continous block of data gets read in 2 parts, the second set of data overwrites the first set of data by the time it gets to the handler. Here's some example logs that I've seen.
BluetoothService: BEGIN mConnectedThread
BluetoothService: a
BluetoothService: bcd
BluetoothHandler: b
BluetoothHandler: bcd
Or:
BluetoothService: BEGIN mConnectedThread
BluetoothService: abc
BluetoothService: d
BluetoothHandler: dbc
BluetoothHandler: d
Or:
BluetoothService: BEGIN mConnectedThread
BluetoothService: ab
BluetoothService: cde
BluetoothHandler: cd
BluetoothHandler: cde
Notice that the second message that gets sent always overwrites the first message's data and only up to the shortest message's length. Also, both messages are always sent before the first message has been processed by mHandler.
I am guessing that I'm a common buffer somewhere is getting overwritten before the the first message is fully processed, but I don't see where. Any suggestions?
Is it possible that you have to use a second byte buffer when creating the message object?
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, copyOfBuffer)
I have a suspicion that mHandler (although I don't know what it is) is keeping a reference to that byte array you send him.
I realize this is an OLD thread, but for posterity...
I just ran across this same issue. Coincidentally, it was also in code based on the google Bluetooth chat sample. My code also talks to a bluetooth device whose data appears in 'snippets' in the mmInStream.read(), resulting in many small messages sent to the handler.
Like the original poster, I found that the messages were being overwritten. I believe this is due to the android implementation of message handling as a light weight messaging mechanism. Specifically, .obtainMessage() allocates from a global pool of message structures to avoid runtime allocations. In keeping with this requirement, they DO NOT COPY THE DATA (/OBJECT) contained within the message, but simply maintain a pointer to the original data. Each message object contains the count of bytes in msg.arg1. In the sample code, if the data within the byte array ('buffer') is changed before the receiving handler has processed the message, the handler still has the original size of the message (contained in msg.arg1), but the buffer data has been updated (/overwritten).
I can see three ways to address this issue:
1. Use the android recommended mechanism (create a bundle of data, and use .setdata() to attach this to the message). I've not tried this, but I expect the bundle creation will result in the data being copied out of the buffer byte array.
2. use new memory for message data. This can be by run-time allocating (but that conflicts with the 'light weight' intention of messaging), or by using multiple statically allocated buffers, and cycling between them. Either approach has issues.
3. perform collection in the low-level thread 'run()', and only send a message for completed Bluetooth messages.
I opted for the third method. In my case, bluetooth messages contain terminated strings, so I use a string builder to collect bytes returned by mmInStream.read(), and only send a message to the handler when the end of line is detected.
A different way is to check if there is already any message with the same name in the Handler's queue with .hasMessages(). Example:
public void run() {
DebugLog.i("BluetoothService", "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
//Check if there is no pending similar message on the queue
if (!mHandler.hasMessages(Constants.MESSAGE_READ)) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
DebugLog.d("BluetoothService", new String(buffer, 0, bytes));
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
DebugLog.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
}
}
Related
First off forgive me if I am mistaken for how blocking works, to my understanding blocking will pause the thread until it is ready, for exsample when reading user input the program will wait until the user hits return.
My problem is that instead of waiting for data to become available it reads bytes with the value 0. Is there a way to block until data becoms available?
The method readBytes is called in a loop.
public byte[] readBytes(){
try{
//read the head int that will be 4 bytes telling the number of bytes that follow containing data
byte[] rawLen = new byte[4];
socketReader.read(rawLen);
ByteBuffer bb = ByteBuffer.wrap(rawLen);
int len = bb.getInt();
byte[] data = new byte[len];
if (len > 0) {
socketReader.readFully(data);
}
return data;
} catch (Exception e){
e.printStackTrace();
logError("Failed to read data: " + socket.toString());
return null;
}
}
If read() returned -1, the peer has disconnected. You aren't handling that case. If you detect end of stream you must close the connection and stop reading. At present you have no way of doing so. You need to reconsider your method signature.
You should use readInt() instead of those four lines of code that read the length. At present you are assuming have read four bytes without actually checking. readInt() will check for you.
This way also you will never get out of sync with the sender, which at present is a serious risk.
in my Client-Server application I found a strange error. I got the following Methods :
sendLoginResponse();
sendPlayerList();
sendCurrentLevelState();
Each Methods sends a byte array to the Client-Side
If I only call 2 of them, everything works fine and the Client-Side gets all the sent byte arrays. But if I call all 3 of them only the first and second one arrive the Client, the order of the following methods doesnt matter. but the Server says all of them were send. To write to the Client iam using the
write(byte[] b, int off, int len); method
all The lenghts within the packages make sense too.
Here comes the strange point:
if I add a Thread.sleep(1000); after the second Method, the third one does now arrive the Client after the sleep. I Have also tried to flush the DataOutputStream after every write call, but this didnt help.
EDIT:
So let's say I'd send 3 Login-Response
The Method's that gives me the byte[]:
public byte[] getLoginResponse(int playerID){
byte[] msg = new byte[4];
short shortMsgLength = 4;
byte[] msgLength = shortToBytes(shortMsgLength);
msg[0] = 2;
msg[1] = msgLength[0];
msg[2] = msgLength[1];
msg[3] = (byte) playerID;
return msg;
}
private byte[] shortToBytes(short value) {
byte[] returnByteArray = new byte[2];
returnByteArray[0] = (byte) (value & 0xff);
returnByteArray[1] = (byte) ((value >>> 8) & 0xff);
return returnByteArray;
}
And the Send Method:
private void sendLoginResponse() {
try{
byte[] msg = rfcObject.getLoginResponse(playerID);
out.write(msg,0,msg.length);
}catch(Exception e){
System.err.println(e.getMessage());
System.exit(0);
}
}
So if I call the sendLoginResponse(); three times in a row, the client only recieves 2 byte-arrays, but the server says it has been sent 3 times. If i add a
Thread.sleep(1000); `after the second Method-Call, everything works fine..`
The Client that reads the message runs in a Thread:
public void run(){
while(true){
try {
byte[] data = new byte[MAX_DATA_SIZE]; // MAX_DATA = 255
byteCount = in.read(data);
} catch (IOException ex) {
handleExceptionError(ex);
}
}
}
thank you!
if I call the sendLoginResponse(); three times in a row, the client only recieves 2 byte-arrays, but the server says it has been sent 3 times.
This is because TCP is a stream-oriented protocol. Meaning it doesn't know or care how your messages are delimited. There's no concept of individual messages in TCP, just a stream of bytes, with the guarantee that the order of bytes is preserved.
So when the sender calls three write, the three byte arrays are simply concatenated over the connection and arrives at the receiver in the same order, but the receiver doesn't necessarily need three read to get all the bytes, and even if it does take three read, the read doesn't necessarily gives you the same byte array passed to each corresponding write.
Your message already have the necessary information to get the individual message back from the byte stream:
// Client code for reading individual messages from a TCP connection
byte type = din.readByte();
// Read the message length, little-endian.
// We cannot use din.readShort because it's big-endian
int lenLo = din.read();
int lenHi = din.read();
short len = (short)(lenLo | (lenHi << 8));
byte [] body = new byte[len];
din.readFully(body);
DataOutputStream and TCP don't lose data.
As almost invariable seen in questions of this nature, the problem is at the receiving end. You are probably assuming that `read()' fills the buffer, and ignoring the count that it returns.
Based on your protocol description in comments, you should be using DataInputStream.readFully() in this circumstance:
byte type = din,readByte();
int length = din.readShort();
byte[] data = new byte[length];
din.readFully(data);
While trying to port some socket code from Java to Node.js (or rather, node-webkit) I came to the part where a handshake is performed between the client and the server. The Java code for this is simple (validation left out):
// C0
byte C0 = 0x03;
out.write(C0);
// C1
long timestampC1 = System.currentTimeMillis();
byte[] randC1 = new byte[1528];
rand.nextBytes(randC1);
out.writeInt((int)timestampC1);
out.writeInt(0);
out.write(randC1, 0, 1528);
out.flush();
// S0
byte S0 = (byte)in.read();
if (S0 != 0x03)
throw new IOException("Server returned incorrect version in handshake: " + S0);
// S1
byte[] S1 = new byte[1536];
in.read(S1, 0, 1536);
I was wondering if there is any way in Node.js to do something similar to Java's Socket.read(). I do not see any in the documentation, but it seems logical because Node.js is more asynchronous.
I have succeeded in writing the sending of the handshake (and confirmed that it works) using this code (methods for sending left out):
//C0
sendByte(sock, 0x03);
//C1
var ts = Date.now();
sock.randomBytes = crypto.randomBytes(1528);
sendInt(sock, ts);
sendInt(sock, 0x0);
sendBytes(sock, sock.randomBytes);
My first thought was to keep track of the connection state and to continue the handshake when a data event is received and the connection has the relevant state. However, the buffer that comes with the data event is limited to 1024 bytes, while the Java code is easily able to read 1528 bytes. The rest of the bytes seem to come in the next data call.
Should I be storing the contents from data in a Buffer and appending whenever the data is received or is there another (easier) way of doing this (a premade module, a method similar to read, ...)?
There is no synchronous read() in that same way, but what can you do in node is something like:
// using a helper function can help normalize things
function readSocket(socket, nb, cb) {
var r = socket.read(nb);
if (r === null) {
socket.once('readable', function() {
readSocket(socket, nb, cb);
});
return;
}
cb(r);
}
// read in 1 byte
readSocket(socket, 1, function(buf) {
// `buf` is a Buffer with `buf.length === 1`
});
I am stuck with the following problem. I have created a connection to a remote echo server. The following method is used for receiving the bytes received from the server:
public byte[] receive() {
byte[] resultBuff = new byte[0];
byte[] buff = new byte[4096];
try {
InputStream in = socket.getInputStream();
int k = -1;
while((k = in.read(buff, 0, buff.length)) != -1) {
System.out.println(k);
byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
resultBuff = tbuff; // call the temp buffer as your result buff
String test = new String(resultBuff);
System.out.println(test);
}
System.out.println(resultBuff.length + " bytes read.");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resultBuff;
}
I am able to get the following response from the server:
Connection to MSRG Echo server established
The problem is that the loop gets stuck at the second execution on in.read(). I understand that this is due the the server not sending any EOF info and the like.
I am not sure which of the following two solutions is correct and in which way to implement it:
Each message coming from the server will be read by a new execution of the receive() method. How do I prevent the in.read() method from blocking?
The loop inside the receive() method should be kept alive until application exit. This means that my implementation is currently using in.read() wrong. In which way should this be implemented.
The key to this question is your use of the word 'message'. There are no messages in TCP, only a byte stream. If you want messages you must implement them yourself: read a byte at a time until you have a complete message, process it, rinse and repeat. You can amortize the cost of the single-byte reads by using a BufferedInputStream.
But there are no messages in an echo server. Your read and accumulate strategy is therefore inappropriate. Just echo immediately whatever you received.
I have another device & application transmitting data in real-time (every few ms) and on my receiving device, I want to:
1) read/receive this data, and
2) use it to update a UI element (a dynamic graph in this case)
The data sender uses a socket in a background service, using AsyncTasks every few ms to send data. To initialize, it does the following:
echoSocket = new Socket(HOST, PORT);
out = new PrintWriter(echoSocket.getOutputStream(), true);
And to periodically send data it does:
static class sendDataTask extends AsyncTask<Float, Void, Void> {
#Override
protected Void doInBackground(Float... params) {
try {
JSONObject j = new JSONObject();
j.put("x", params[0]);
j.put("y", params[1]);
j.put("z", params[2]);
String jString = j.toString();
out.println(jString);
} catch (Exception e) {
Log.e("sendDataTask", e.toString());
}
return null;
}
}
How should I go about receiving this data in my application? Should I also use a background service with AsyncTasks that try to read from the socket every few ms? How about communicating with the UI thread?
There are many ways to do this. The simplest would be to use blocking reads in the doInBackground method of an AsyncTask and call publishProgress() to forward the new data to the UI thread.
Then implement onProgressUpdate with code (running in the UI thread) that updates the screen.
You should be aware that your read may not receive the entire message that you sent -- you may need to read more data and append it to the input received so far until you have an entire JSON message.
By blocking reads, I mean something like this (in pseudo code):
open a socket connected to the sender
is = socket.getInputStream()
initialize buffer, offset, and length
while the socket is good
bytesRead = is.read(buffer, offset, length)
if(bytesRead <= 0)
bail out you have an error
offset += bytesRead;
length -= bytesRead
if(you have a complete message)
copy the message out of the buffer (or parse the message here into
some other data structure)
publishProgress(the message)
reset buffer offset and length for the next message.
(remember you may have received part of the following message)
end-if
end-while
The copy-out-of-the-buffer is necessary because the onProgressUpdate does not happen immediately so you need to be sure the next message does not overwrite the current one before it gets handled.