I have troubles with my program when i need to send Strings from my server bluetooth-socket to my client bluetooth-socket.
Everything works fine as long as I am only sending one String at a time (for example chatting) but if I need to write more Strings at a short period of time (to interchange informations), the Strings will not get seperated from the client code. For example if I'm sending "FirstUser" and right after that "SecondUser" the client does not read "FirstUser" and then "SecondUser". It will read "FirstUserSecondUser". How can I avoid this behaviour?
Edit: If I let the Thread sleep before it is able to send a new message, it reads the right strings but this solution is not working fine for my need.
Server-Code: sending to all clients(edited)
public synchronized void sendToAll(String message)
{
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
publishProgress(message);
for(OutputStream writer:outputList) {
try {
writer.write(message.getBytes());
writer.flush();
} catch (IOException e) {
System.out.println("Some-Error-Code");
}
}
}
Server-Code: reading from a client:
public void run() {
String nachricht;
int numRead;
byte[] buffer = new byte[1024];
while (runningFlag)
{
try {
if((numRead = inputStream.read(buffer)) >= 0) {
nachricht = new String(buffer, 0, numRead);
serverThread.handleMessage(nachricht);
}
}
catch (IOException e) {
this.cancel();
e.printStackTrace();
}
}
}
Client-Code: reading from server(edited)
#Override
protected Void doInBackground(Integer... ints) {
String nachricht = new String();
byte[] buffer = new byte[1024];
int numRead;
while (runningFlag)
{
try {
if(((numRead = inputStream.read(buffer)) >= 0)) {
nachricht = new String(buffer, 0, numRead);
publishProgress(nachricht);
}
}
catch (IOException e) {
clientGame.finish();
e.printStackTrace();
}
}
return null;
}
Client-Code: writing to server
public synchronized void write(String nachricht)
{
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
outputStream.write(nachricht.getBytes());
outputStream.flush();
} catch (IOException e) {
this.cancel();
e.printStackTrace();
}
}
I appreciate every little help :) .
You need to encapsulate your data item to avoid concatenation.
It means that you have to write and read a whole data item before continuing.
You should have some utility methods to do that instead of directly using methods of OutputStream and InputStream :
public static void writeItem(OutputStream out, String s) throws IOException
{
// Get the array of bytes for the string item:
byte[] bs = s.getBytes(); // as bytes
// Encapsulate by sending first the total length on 4 bytes :
// - bits 7..0 of length
out.write(bs.length); // modulo 256 done by write method
// - bits 15..8 of length
out.write(bs.length>>>8); // modulo 256 done by write method
// - bits 23..16 of length
out.write(bs.length>>>16); // modulo 256 done by write method
// - bits 31..24 of length
out.write(bs.length>>>24); // modulo 256 done by write method
// Write the array content now:
out.write(bs); // Send the bytes
out.flush();
}
public static String readItem(InputStream in) throws IOException
{
// first, read the total length on 4 bytes
// - if first byte is missing, end of stream reached
int len = in.read(); // 1 byte
if (len<0) throw new IOException("end of stream");
// - the other 3 bytes of length are mandatory
for(int i=1;i<4;i++) // need 3 more bytes:
{
int n = in.read();
if (n<0) throw new IOException("partial data");
len |= n << (i<<3); // shift by 8,16,24
}
// Create the array to receive len bytes:
byte[] bs = new byte[len];
// Read the len bytes into the created array
int ofs = 0;
while (len>0) // while there is some byte to read
{
int n = in.read(bs, ofs, len); // number of bytes actually read
if (n<0) throw new IOException("partial data");
ofs += n; // update offset
len -= n; // update remaining number of bytes to read
}
// Transform bytes into String item:
return new String(bs);
}
Then you use these methods both for server & client to read and write your String items.
Related
I coded this packet handler but I can imagine scenarios in which it will get stuck or won't be able to read incomplete data. My questions are:
Should I use two buffers, one for the current incoming data and other to append incomplete data to?
I'm being stupidly over-complicated?
Code:
byte[] buffer;
int bufferLength;
int bytesRead;
buffer = new byte[1024];
while (bluetoothConnected) {
try {
// Wait for packet header
if (mmInStream.available() >= 8) {
bufferLength = mmInStream.read(buffer);
bytesRead = 0;
// Parse every packet
while (true) {
int commandType = ByteBuffer.wrap(buffer, 0, 2).order(ByteOrder.LITTLE_ENDIAN).getShort();
int payloadSize = ByteBuffer.wrap(buffer, 2, 2).order(ByteOrder.LITTLE_ENDIAN).getShort();
int packetSize = PACKET_HEADER_SIZE + payloadSize;
// Break if payload is incomplete
if (bufferLength < (bytesRead + packetSize)) {
// Append to other buffer
break;
}
byte[] packet = new byte[packetSize];
System.arraycopy(buffer, bytesRead, packet, 0, packetSize);
parsePacketSequence(socket, packet);
bytesRead += packetSize;
// Break if all bytes are read
if (bufferLength == bytesRead)
{
break;
}
// Break if more bytes are needed
// Packet header incomplete
if ((bufferLength - bytesRead) < PACKET_HEADER_SIZE)
{
// Append to other buffer
break;
}
}
}
}
catch (IOException e) {
bluetoothConnected = false;
Log.d(TAG, "Error " + e);
break;
}
}
Should I use two buffers, one for the current incoming data and other to append incomplete data to?
No.
I'm being stupidly over-complicated?
Yes.
Here's a simple version using DataInputStream:
DataInputStream din = new DataInputStream(mmInStream);
while (bluetoothConnected) {
try {
// Read packet header
int commandType = swap(din.readShort());
int payloadSize = swap(din.readShort());
int packetSize = PACKET_HEADER_SIZE + payloadSize;
byte[] packet = new byte[packetSize];
din.readFully(packet);
parsePacketSequence(socket, packet);
}
catch (IOException e) {
bluetoothConnected = false;
Log.d(TAG, "Error " + e);
break;
}
}
The swap() method which converts a short in litte-endian byte order to Java byte order is left as an exercise for the reader.
NB I don't see how parsePacketSequence() can work if it doesn't know commandType.
E&OE
Is there a way to read all InputStream values at once without a need of using some Apache IO lib?
I am reading IR signal and saving it from the InputStream into the byte[] array. While debugging, I have noticed that it works only if I put a delay there, so that I read all bytes at once and then process it.
Is there a smarter way to do it?
CODE:
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[100];
int numberOfBytes;
removeSharedPrefs("mSharedPrefs");
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
numberOfBytes = mmInStream.read(buffer);
Thread.sleep(700); //If I stop it here for a while, all works fine, because array is fully populated
if (numberOfBytes > 90){
// GET AXIS VALUES FROM THE SHARED PREFS
String[] refValues = loadArray("gestureBuffer", context);
if (refValues!=null && refValues.length>90) {
int incorrectPoints;
if ((incorrectPoints = checkIfGesureIsSameAsPrevious(buffer, refValues, numberOfBytes)) < 5) {
//Correct
} else {
//Incorrect
}
}
saveArray(buffer, numberOfBytes);
}else{
System.out.println("Transmission of the data was corrupted.");
}
buffer = new byte[100];
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, numberOfBytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothChatService.this.start();
break;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Edit:
My old answer is wrong, see EJPs comment! Please don't use it. The behaviour of ByteChannels depend on wether InputStreams are blocking or not.
So this is why I would suggest, you just copy IOUtils.read from Apache Commons:
public static int read(final InputStream input, final byte[] buffer) throws IOException {
int remaining = buffer.length;
while (remaining > 0) {
final int location = buffer.length - remaining;
final int count = input.read(buffer, location, remaining);
if (count == -1) { // EOF
break;
}
remaining -= count;
}
return buffer.length - remaining;
}
Old answer:
You can use ByteChannels and read into a ByteBuffer:
ReadableByteChannel c = Channels.newChannel(inputstream);
ByteBuffer buf = ByteBuffer.allocate(numBytesExpected);
int numBytesActuallyRead = c.read(buf);
This read method is attempting to read as many bytes as there is remaining space in the buffer. If the stream ends before the buffer is fully filled, the number of bytes actually read is returned. See JavaDoc.
I'm trying to decrypt the content of a file bigger than 1k for a "RETR" action of an FTP Client and I'm encountering this kind of exception.
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.DESCipher.engineDoFinal(DESCipher.java:314)
at javax.crypto.Cipher.doFinal(Cipher.java:2145)
This is the code that is giving me problem:
byte[] encontent = new byte[0];
byte[] buff = new byte[1024];
int k = -1;
while((k = bis.read(buff, 0, buff.length)) > -1) {
byte[] tbuff = new byte[encontent.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(encontent, 0, tbuff, 0, encontent.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, encontent.length, k); // copy current lot
encontent = tbuff; // call the temp buffer as your result buff
}
System.out.println(encontent.length + " bytes read.");
byte [] plain = dcipher.doFinal(encontent, 0,encontent.length);
The length of the byte array encontent is always an 8-bit multple, because it is the result of a previous encryption.
Here it's the code that starts the operation from server side:
public void download (String pathfile)
{
Socket DataSock = null;
try {
DataSock = new Socket (clientAddr, TRANSMISSION_PORT);
if (DataSock.isConnected())
{
BufferedOutputStream bos = new BufferedOutputStream (DataSock.getOutputStream());
int size=0;
int blocks=0;
int resto=0;
if (pathfile.endsWith(".txt"))
{
String text = readTxtFile (pathfile);
byte [] encontent = ecipher.doFinal(text.getBytes("UTF8"));
sendFile (bos,encontent);
} else {
byte [] content = readFile (pathfile);
byte [] encontent = ecipher.doFinal(content);
sendFile (bos, content);
}
}
} catch (Exception e)
{
e.printStackTrace();
} finally {
try {
DataSock.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
The final block must contain 8 bytes. If it does not, one has to pad until its 8 bytes wide. Your assumption is wrong.
Have a look at https://stackoverflow.com/a/10427679/867816
I was wondering which is the best way to get the title from a disk image in .iso or .cue+.bin format,
Is there any java library that can do this or should I read from the file header?
UPDATE:
I managed to do it, i was particularly interested in PSX ISOs title. It's 10 bytes long and this is a sample code to read it:
File f = new File("cdimage2.bin");
FileInputStream fin = new FileInputStream(f);
fin.skip(37696);
int i = 0;
while (i < 10) {
System.out.print((char) fin.read());
i++;
}
System.out.println();
UPDATE2: This method is better:
private String getPSXId(File f) {
FileInputStream fin;
try {
fin = new FileInputStream(f);
fin.skip(32768);
byte[] buffer = new byte[4096];
long start = System.currentTimeMillis();
while (fin.read(buffer) != -1) {
String buffered = new String(buffer);
if (buffered.contains("BOOT = cdrom:\\")) {
String tmp = "";
int lidx = buffered.lastIndexOf("BOOT = cdrom:\\") + 14;
for (int i = 0; i < 11; i++) {
tmp += buffered.charAt(lidx + i);
}
long elapsed = System.currentTimeMillis() - start;
// System.out.println("BOOT = cdrom:\\" + tmp);
tmp = tmp.toUpperCase().replace(".", "").replace("_", "-");
fin.close();
return tmp;
}
}
fin.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Just start reading after 32768 bytes (unused by ISO9660) in 2048 byte chunks (Volume Descriptor). The first byte determines the type of the descriptor, and 1 means Primary Volume Descriptor, which contain the title after the first 7 bytes (which are always \x01CD001\x01). The next byte is a NUL (\x00) and it is followed by 32 bytes of system and 32 bytes of volume identifier, the latter usually known and displayed as title. See http://alumnus.caltech.edu/~pje/iso9660.html for a more detailed description.
i am trying to send integers to Android device via Bluetooth communication. My question is how do i read array of charcters from the inpustream?
This is a partion of my server code Java:
try {
outStream = connection.openOutputStream();
int numbers = (int) (Math.random() * 10);
outStream.write(numbers);
System.out.println(numbers);
} catch (IOException e) {
e.printStackTrace();
}
The objective is to Android reads the integers that the server sends. I have also tryd to use PrintWriter method to send data(randome numbers) like this:
outStream = connection.openOutputStream();
pWriter = new PrintWriter(new OutputStreamWriter(outStream));
int numbers = (int) (Math.random() * 10);
pWriter.write(numbers);
System.out.println(numbers);
pWriter.flush();
pWriter.close();
if use this method print.write, i know that this it send only single charchters, so my question is how do i send array of charchters to Android?
this the portion of my Android code:
public void run() {
int data = in.read(buffer);
while (true) {
try {
byte[] buffer = new byte[1024];
int data;
data = in.read(buffer);
data = in.read(buffer, 0, buffer.length);
} catch (IOException ex) {
Log.e(TAG_IOThread, "disconnected", ex);
break;
}
}
}
It was indeed the DataOutpustream, i used writeInt() method and on the server i changed to readInt(); I thought it was posibble to use OutputStream to send integers and InputStream to receive it.