I have probably been staring at this too long and can't see what the problem is.
I have a server which accepts multiple client connections and saves the sockets. The server can then send out control messages to the clients to perform tasks and, among other things, I want to send files out to all the connected clients but the client only seems to receive part of them.
For testing purposes I have a randomly generated text file 69075 bytes but although it seems like whole whole file is sent, the client only receives upto around 57000 bytes (varies). I have added a button on the server app which lets me close the client socket and when I do that the client receives -1 followed by the rest of the missing file.
Server sending file:
try {
getClientList().get(0).setLocked(true);
byte [] mybytearray = new byte [1024];
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));
OutputStream os = getClientList().get(0).getmSocket().getOutputStream();
Boolean eof = false;
int bytesRead;
int total = 0;
do {
bytesRead = bis.read(mybytearray, 0, mybytearray.length);
if (bytesRead != -1) {
os.write(mybytearray, 0, bytesRead);
total += bytesRead;
Log.d(TAG_SF, "Total: "+total+" :Sent: "+ bytesRead);
} else {
eof = true;
Log.d(TAG_SF, "EOF, Total sent: " + total);
}
} while (!eof);
os.flush();
bis.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
getClientList().get(0).setLocked(false);
}
A message is sent to the clients with the file name and file size before the file is send and it is received ok.
Client receiving file:
try {
int total = 0;
byte[] myByteArray = new byte[1024];
int bytesRead;
InputStream is = serverSocket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(path+SD_DIRECTORY+fileName));
do {
bytesRead = is.read(myByteArray, 0, myByteArray.length);
if (bytesRead != -1){
bos.write(myByteArray, 0, bytesRead);
total = total+bytesRead;
Log.e(TAG,"Total > "+total+ ": No Bytes : "+bytesRead);
} else {
Log.e(TAG,"EOF, total received: "+total);
break;
}
} while (total < fileLength); //fileLength and filename are sent before file
Log.e(TAG,"Total > "+total+ ": No Bytes : "+bytesRead);
bos.flush();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
The problem was not with the code for sending and receiving, it works fine.
I was sending a message to the client first with a control code indicating a file was to be send, followed by the file size and file name. The client then waits for the file but the server started sending before the client was ready and was missing the start of the file.
To test, put the server thread to sleep for a couple of seconds after sending the file name and before sending the file and it works fine. I will probably have the client send a 'ready' message to the server as a better solution.
EDIT:
Although this worked, it is not the answer, it does seem to be related to using both buffered and unbuffered streams (see EJP comment). Will do a bit of re writing and update accordingly. Not sure of SO protocol, should I delete a wrong answer?
EDIT (again)
EJPs comment is absolutely correct, it was related to having a buffered input stream open to receive the file name and then opening an unbuffered stream elsewhere to transfer the file. My knowledge is limited in this area (and generally) so I just re wrote to use the same unbuffered stream for both.
Related
Based on SDK's bluetoothchat example I'm working on an app that transmits strings between an android device and arduino.
I've the folowing issues:
1- If I use this code I loose the first byte sent by arduino:
// Keep listening to the InputStream while connected
while (true) {
try {
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes,-1, buffer).sendToTarget();
But This way it works :
bytes = mmInStream.available();
if(bytes != 0) {
SystemClock.sleep(100); //pause and wait for rest of data.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}
Any explanation please?
2- Arduino sends the string "OK" when recieves a string from the device.
How to use this as an ACK(nowledgment) in my app ?
I tried this but with no success:
String ack = ""; //global variable
sendstring("test string");// send a test string to arduino
SystemClock.sleep(100); //wait for arduino response
if(ack.equals("OK")) txtv.setText(" well received"); //well done
in the handler:
if(msg.what == Bluetooth.MESSAGE_READ){
String receivedstring = new String((byte[]) msg.obj, 0, msg.arg1);
ack = receivedstring ;
I don't get ack = "OK" , and " well received" is not displayed in the text view !!
Many thanks for ur help
Hi i dont know that much about blutoothchat but i may have an anwser to your first question. If you dont already have an answer.
// Keep listening to the InputStream while connected
while (true) {
try {
bytes = mmInStream.read(buffer); // it may not work because its not reading from the first line unlike this: bytes = mmInStream.read(buffer, 0, bytes);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes,-1, buffer).sendToTarget();
I'm trying to send the pictures between two android devices, but there is a transmission problem I can't figure out. Someone tell me to revise the wile loop, but it still do not work.
When I tested my project on the device, there wasn't problem with the connection. But, as the transmission task started, the sending client was stopped and "transfer erro" msg showed up on the receiver.
Is there anyone knows what can I do to my program? Here are my two mainly parts of sending and receiving.
I'll be very appreciative of any help. Thank you.
sending part:
s = new Socket("192.168.0.187", 1234);
Log.d("Tag====================","socket ip="+s);
File file = new File("/sdcard/DCIM/Pic/img1.jpg");
FileInputStream fis = new FileInputStream(file);
din = new DataInputStream(new BufferedInputStream(fis));
dout = new DataOutputStream(s.getOutputStream());
dout.writeUTF(String.valueOf(file.length()));
byte[] buffer = new byte[1024];
int len = 0;
while ((len = din.read(buffer)) != -1) {
dout.write(buffer, 0, len);
tw4.setText("8 in while dout.write(buffer, 0, len);");
}
dout.flush();
the sending part can work smoothly and no erro showed up after the while loop overed
receiving part:
try {
File file = new File("/sdcard/DCIM/img1.jpg");
DataInputStream din = new DataInputStream(new BufferedInputStream(client.getInputStream()));
bis = new BufferedInputStream(client.getInputStream());
Log.d("Tag====================","din="+s);
FileOutputStream fos = new FileOutputStream(file);
dout = new DataOutputStream(new BufferedOutputStream(fos));
byte[] buffer = new byte[1024];
int len = 0;
while ((len = bis.read(buffer)) != -1) {
dout.write(buffer, 0, len);
}
dout.flush();
dout.close();
} catch (Exception e) {
handler.post(new Runnable() {
public void run() {
tw1.setText("transmission error");
}});
About the receiving part seems even stuck at the "DataInputStream din = new DataInputStream(new BufferedInputStream(client.getInputStream()));" and catch the exception.
Thanks again.
You're writing the file length with writeUTF() but you're never reading it. If you're going to close the socket after sending the image, you don't need the length: just send and then close the socket. If you do need the length, read it, with readUTF(), and then read exactly that many bytes from the socket to the target.
And if you need the length it would make more sense to send it with writeInt() or writeLong() than to convert the number to a string, convert that to writeUTF() format, convert that back to a string at the other end with readUTF(), and then convert that back to an int or a long. That also implies using readInt() or readLong() as appropriate, of course.
EDIT
For about the millionth time (wish I had a $ for each time), the canonical way to copy a stream in Java is:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
where 'count' is an int and 'buffer' is a byte array with length > 0, preferably 8192 or more. Note that you have to loop; you have to store the read() result in a variable; you have to test that variable; and you have to use it in the write() call.
I try to create an application that can download files from a server in order to measure the speed that I can get with the particular server. I do this by using the Asynctask class. All the files that I want to download are located on the same directory. My question is, how can I download the subsequent files by keeping the connection and not by creating every time a new one? I know that for a TCP connection, there must be a 3-way-handshake established, before downloading a file. I want to connect to the server and then keep the connection and perform the download.
My code looks like this
#Override
protected Integer doInBackground(String... sUrl) {
try {
speed=0; //initial value
int i=0;
while ((i<sUrl.length)) {
URL url = new URL(sUrl[i]); //sUrl[] contains the links that i want
// for example http://myserver.net/file1.jpg, http://myserver.net/file2.jpg ... etc
URLConnection connection = url.openConnection();
connection.connect(); //connection to be established 3WAY HANDSHAKE
int fileLength = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(file);
byte data[] = new byte[1024];
long total = 0;
int count;
long start = System.currentTimeMillis();
while ((count = input.read(data)) != -1) {
total += count;
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
long finish = System.currentTimeMillis();
long tempSpeed= (fileLength *8)/(finish-start);
if (tempSpeed>speed) {
speed=tempSpeed;
}
output.flush();
output.close();
input.close(); // connection is closed
i++;
}
}catch(Exception e) {
exceptions.add(e);
}
return 1;
}
By creating a new connection I loose time (for the download speed), because of the 3way handsharke . Also when transfering files in TCP, there is something called a tcp window (when you dowload data, initialy you start with low speed transmission, and if the connection is good this rate increases).
How can I do the above without creating and tearing down the connection for each file?
Looking at you code, you keep receiving until the socket is close at the other side, so there is no way of using the same socket since it's closed. If you can program both, the server and the client, then, I would suggest one possible way of doing it, and that is with a protocol, instead of receiving the file directly, the first packet you get is an integer which indicates the size of the file you're going to receive. If that length is 0 (cero) it means there no more files and the connection should be closed.
At the server:
While (the_are_files_to_send)
{
Socket.write((int) FileSize);
Socket.write(file's content);
}
Socket.Write(0); // No more files;
Socket.Close();
At the Client:
While ((size = Socket.read(buffer, 0, 4)) != -1)
{
int FileLength = convert_to _int(buffer);
if (FileLength==0) break;
Socket.read(FileLength bytes);
}
Socket.Close();
I need to pass an Intent by bluetooth. Peviously I created the game and I save the caracteristics of the game in a class type singleton.
What I want to do is pass this information to the other device that I'm already connected and start de game that previously me or he/she created.
How can I send this information and the activity of the game?
I use andengine to make all the game.
Thanks!
I think this site may help you. There are a few methods, but you want the last one mentioned in the OP.
public void sendFile(Uri uri, BluetoothSocket bs) throws IOException {
BufferedInputStream bis = new BufferedInputStream(getContentResolver().openInputStream(uri));
OutputStream os = bs.getOutputStream();
try {
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
// we need to know how may bytes were read to write them to the byteBuffer
int len = 0;
while ((len = bis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} finally {
bis.close();
os.flush();
os.close();
bs.close();
}
}
Hope this helps.
From my Android app I try to download from the windows Azure blob storage using the following URL: http://iclyps.blob.core.windows.net/broadcasts/23_6.mp4
The resulting file is corrupt when I download it from within my app. Same error occurs when I download it using the default Browser or Chrome. Also from the Easy Downloader app, the same error occurs. Only a download from my PC or using Firefox Beta from the Android device (or emulator), the file is retrieved correctly.
I use the following code (snippet):
try {
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//set up some things on the connection
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
//and connect!
urlConnection.connect();
bis = new BufferedInputStream(urlConnection.getInputStream(), BUFSIZE);
bos = new BufferedOutputStream(
context.openFileOutput(TMPFILE, Context.MODE_PRIVATE), BUFSIZE);
/*
* Read bytes to the buffer in chunks of BUFSIZE bytes until there is nothing more to read.
* Each chunk is written to the output file.
*/
byte[] buf = new byte[BUFSIZE];
int nBytes = 0;
int tBytes = 0;
while ((nBytes = bis.read(buf, 0, BUFSIZE)) > 0) {
bos.write(buf, 0, nBytes);
tBytes += nBytes;
}
if (tBytes == 0) throw new Exception("no bytes received");
bos.flush();
MobyLog.d(TAG, "download succeeded: #bytes = " + Integer.toString(tBytes));
return true;
} catch (Exception e) {
MobyLog.e(TAG, "download failed: " + e);
context.deleteFile(TMPFILE); // remove possibly present partial file.
return false;
} finally {
if (bis != null) try { bis.close(); } catch (IOException e) {MobyLog.e(TAG, "bis close exception: " + e); };
if (bos != null) try { bos.close(); } catch (IOException e) {MobyLog.e(TAG, "bos close exception: " + e); };
}
Analyzing the files shows that the first part (about 700K) of the original file is repeated a number of times in the corrupted files, resulting in an invalid mp4 file.
Putting the file on another webserver (Apache/IIS), and downloading the file from that location does result in a correct download.
Has anyone experienced a similar problem performing a download from Azure? Can someone provide a solution?
Cheers,
Harald...
Have you tried using the azure-sdk-for-java in your android app?
Our scenario is slightly different in that we using the sdk to pull and push images from blob storage to a custom android app. But the fundamentals should be the same.