is there a quicker way to copy bytes from one array to another without iteration ?
I'm reading bytes via Bluetooth from the input stream
public void run() {
byte[] buffer = new byte[100]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
This sends a random number of bytes to the handler.
I then read these and put them into an array to then process the data when the download is complete. The data being sent from a PIC micro is 6055 bytes long.
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case SUCCESS_CONNECT:
// Connected so start connected thread
btSocket = (BluetoothSocket) msg.obj;
byteCount = 0;
arrayCount = 0;
mConnectedThread = new FullDataActivity.ConnectedThread(btSocket);
mConnectedThread.start();
mConnectedThread.write(getFullDataConByte); // Send 255 to start
break;
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
// iterate through obj and copy bytes to fullDataChunk array
for (int a = 0; a < msg.arg1; a++) {
fullDataChunk[byteCount] = readBuf[a];
Log.d("readBuf[a] = ",Integer.toString(readBuf[a] & 0xFF));
byteCount++;
}
// if all bytes done process
if (byteCount == 6055) {// process data when complete.
My handler is missing bytes somewhere and corrupting the data when its copying them in the for loop. I don't know if the run method is sending new bytes to the handler before the rest are processed in the for loop.
I've done a Log of the bytes sent in the Run and they are right. It's when the handler is processing that they go wrong.
I either need to ensure the data sent is processed before new data is sent, or copy the data to the array quicker ?
Anyone any ideas.
The fastest way to copy an array should be by using System.arraycopy()
.
Did this in the run, then the handler receives full array without errors.
public void run() {
byte[] fullBuffer = new byte[6055];
byte[] buffer = new byte[100]; // buffer store for the stream
int bytes; // bytes returned from read()
int bytesCount = 0;
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
System.arraycopy(buffer,0,fullBuffer,bytesCount,bytes);
bytesCount = bytesCount + bytes;
Log.d("FD Read - ", Integer.toString(bytesCount));
if(bytesCount >= 6055){
h.obtainMessage(RECIEVE_MESSAGE, bytesCount, -1, fullBuffer).sendToTarget(); // Send to message queue Handler
Log.d("FD Read - ", "Message sent");
bytesCount = 0;
Log.d("FD Read - ", "bytesCount re-set");
}
//h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
Related
I am trying to read bytes received via a bluetooth connection and convert it to String
Monitor input stream
public void run() {
Log.i(TAG, "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);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothChatService.this.start();
break;
}
}
}
MainActivity when I receive, the log statement does not seem to get called if there is multiple lines. If it is just a single line, it's fine
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
String readMessage = new String(readBuf, 0, msg.arg1);
Log.d(TAG, "Incoming message: " + readMessage); // does not get called when there's a linebreak.
When I try to check if the string contains certain info as such, it doesn't get called even though the String I received does contain it.
For example, given if I receivedreadMessage = "Obstacle String\nStart of 2nd line"
The following statement doesn't get called
if (readMessage.contains("Obstacle String"))
But when I try to set the readMessage to some TextView, it is able to display the string correctly.
For some reason Android logcat does not seems to handle \r
So, I trimmed the string as such
readMessage = readMessage.replaceAll("\r", "");
I have an app that transfer serializable object via bluetooth.
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, 0, buffer.length);
// manage bytes
}
catch (IOException e)
{
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
}
I need a next scenario :
client push object to server
server read bytes related to buffer size( in my case - 1024 bytes)
server deserialize bytes into my object.
So,
How i can know am i read whole object or just a part of him?
P.S. Object may have big size, for ex - more than 100mb.
You say you're sending serializable objects, by which I understand that you are using ObjectOutputStream.writeObject().
In which case you shouldn't be reading bytes at all, you should be using ObjectInputStream.readObject().
It's not the answer, just a proposal(suggestion).
What if i use a markup bytes for detect BEGIN and END of object?
For example :
final byte BEGIN = 0b00000000;
final byte END = 0b00001111;
byte[] BEGIN_OBJECT_BLOCK = new byte[1024];
byte[] END_OBJECT_BLOCK = new byte[1024];
for(int i=0; i<1024; i++) {
BEGIN_OBJECT_BLOCK[i] = BEGIN;
}
//send BEGIN_OBJECT_BLOCK
byte[] tmpArray = new byte[1024];
// split object into blocks of 1024 bytes
// for each block -> send to server
for(int i=0; i<1024; i++) {
END_OBJECT_BLOCK[i] = END;
}
//send END_OBJECT_BLOCK
1) How about this idea?
2) What the negative side of this?
3) What is the probability\chance of that my BEGIN_OBJECT_BLOCK will be equals to byte sequence(byte[1024]) in object?
I'm trying to implement a communication system with an automatic repeat request strategy. I use three classes: Transmitter, Channel, Receiver. I have a maximum number of byte for message (window). But when I receive the byte sent, sometimes I receive less bytes than window. Why?
My code is this:
Transmitter
int n = 0;
int remaining, length;
while (n<channelBytes.length) {
remaining = channelBytes.length-n;
length = (remaining<window)? remaining : window;
outputStream.write(channelBytes,n,length);
// wait for the ack
byte[] b = new byte[4];
channel.socket().setSoTimeout(2000);
inputStream.read(b);
n += ByteBuffer.wrap(b).getInt();
}
Channel
bytes = new byte[SystemModel.WINDOW];
while(true) {
// receive from Tx
upInputStream.read(bytes);
// insert channel error
insertError(bytes);
Thread.sleep(propagationDelay + transmissionDelay);
// send bytes to Rx
downOutputStream.write(bytes);
// wait for the ack from Rx
clientChannelDown.socket().setSoTimeout(2000);
byte[] ack = new byte[4];
downInputStream.read(ack);
// send ack to Tx
upOutputStream.write(ByteBuffer.allocate(4).put(ack).array());
}
Receiver
byte[] b = new byte[SystemModel.WINDOW];
while (true) {
try {
int received = inputStream.read(b);
channelCoding.decodePartially(b);
}catch (SocketTimeoutException te){
break;
} catch (IOException e) {
e.printStackTrace();
} catch (DataFormatException e) {
// send ack
int ack = Integer.parseInt(e.getMessage());
try {
outputStream.write(ByteBuffer.allocate(4).putInt(ack).array());
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
In the Receiver, the array of bytes "b" is not always the length of the window.
Invalid code. See the Javadoc. InputStream.read(byte[] [,...]) isn't obliged to transfer more than one byte, and it is never valid to call it without storing the result into a variable. If you're expecting more than one byte, you have to loop, or use DataInputStream.readFully().
The canonical way to copy streams in Java is as follows:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
For ByteBuffers with Channels it is as follows:
while (in.read(buffer) > 0 || buffer.position() > 0)
{
buffer.flip();
out.write(buffer);
buffer.compact();
}
If you code correctly there is no need to insert sleeps into network code.
E&OE
I have searched and searched and everything I have found has been helpful but I keep getting an out of memory error. The images I send are .06 MB so I know the problem isn't from decoding the byte[] into a bitmap. When I remove the while loops this works like a charm for one frame but I want multiple frames. I am getting a byte[] and sending it to a different device using sockets but I am at a loss how to do this. My problem is that I don't send and receive the correct byte[] length. This is what i am doing currently.
while (count != -1) {
//first send the byte[] length
dataOutputStream.writeInt(sendPackage.length);
//pass a byte array
publishProgress("sending file to client");
showMyToastOnUiThread(String.valueOf(sendPackage.length));
outputStream.write(sendPackage, 0, sendPackage.length);
outputStream.flush();
}
Receive byte[] on different device:
int count = inputStream.read();
while (count != -1) {
int byteArrayLength = dataInputStream.readInt();
Log.i(MainActivity.TAG, "Starting convert to byte array");
byte[] receivedBytes = convertInputStreamToByteArray(inputStream, byteArrayLength);
Bitmap bitmap = BitmapFactory.decodeByteArray(receivedBytes, 0, receivedBytes.length);
publishProgress(bitmap);
}
//convert inputstream to byte[]
public byte[] convertInputStreamToByteArray(InputStream inputStream, int readLength) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] data = new byte[readLength];
try {
Log.i(MainActivity.TAG, "Starting convert to byte array while loop");
int readTotal = 0;
int count = 0;
while (count >= 0 && readTotal < readLength) {
count = inputStream.read(data, readTotal, readLength - readTotal);
if (readLength > 0) {
readTotal += count;
}
}
Log.i(MainActivity.TAG, "Finished convert to byte array while loop");
} catch (IOException e) {
Log.e(MainActivity.TAG, "error: " + e.getMessage());
e.printStackTrace();
}
return data;
}
This is the problem:
int count = inputStream.read();
while (count != -1) {
You're consuming a byte and then ignoring it. That means the next value you read (the size) will be incorrect. You need a different way of telling whether you're at the end of the stream. Some options:
Send a -1 when you're finished; that way you can stop as soon as readInt returns -1
If you know it, send the number of images you're going to send before you start sending them
Use mark(1), then read(), then reset() - if your stream supports marking. I don't know whether it will or not. You could always wrap it in BufferedInputStream if not.
Reimplement DataInputStream.readInt yourself in a way which detects the end of the stream as being an expected possibility instead of throwing an exception
Just catch an exception in readInt (not nice - getting to the end of the stream isn't really exceptional)
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.