I'm trying to download a file using socket and server in java.
myClient = new Socket(address,port);
myClient.setSoTimeout(MyFileManager.TIME_OUT);
in = new DataInputStream(myClient.getInputStream());
out = new DataOutputStream(myClient.getOutputStream());
File requestedFile = new File(_fileManager.getDir()+fileName); //creating the new file
// requestedFile.createNewFile(); //now it does
fos = new FileOutputStream(requestedFile);
long size = in.readLong(); //get the size
for (int i=1; i<=size; i++) {
try {
fos.write(in.read());
}
catch (IOException e) {
e.printStackTrace();
}
}
I'm sending the other side the file size and then sending each byte,
right before the bytes end, it throws the above exception, saying conncetion reset.
what could be the problem?
Thank you!
Why do you think that this line returns the number of bytes in the stream??
long size = in.readLong(); //get the size
You should do in.read() until it returns -1.
I think that the loop should be something like:
for (int i=0; i<size; i++)...
Since streams are 0 based.
Also, you might want to keep reading until you hit the EOF rather than reading a specific number of bytes. See this tutorial to learn how :)
Related
I have a problem when the user upload large files (> 1 GB) (I'm using flow.js library), it creates hundred of thousand small chunked files (e.g 100KB each) inside temporary directory but failed to merge into single file, due to MemoryOutOfException. This is not happened when the file is under 1 GB. I know it sound tedious and you probably suggest me to increase the XmX in my container-but I want to have another angle besides that.
Here is my code
private void mergeFile(String identifier, int totalFile, String outputFile) throws AppException{
File[] fileDatas = new File[totalFile]; //we know the size of file here and create specific amount of the array
byte fileContents[] = null;
int totalFileSize = 0;
int filePartUploadSize = 0;
int tempFileSize = 0;
//I'm creating array of file and append the length
for (int i = 0; i < totalFile; i++) {
fileDatas[i] = new File(identifier + "." + (i + 1)); //indentifier is the name of the file
totalFileSize += fileDatas[i].length();
}
try {
fileContents = new byte[totalFileSize];
InputStream inStream;
for (int j = 0; j < totalFile; j++) {
inStream = new BufferedInputStream(new FileInputStream(fileDatas[j]));
filePartUploadSize = (int) fileDatas[j].length();
inStream.read(fileContents, tempFileSize, filePartUploadSize);
tempFileSize += filePartUploadSize;
inStream.close();
}
} catch (FileNotFoundException ex) {
throw new AppException(AppExceptionCode.FILE_NOT_FOUND);
} catch (IOException ex) {
throw new AppException(AppExceptionCode.ERROR_ON_MERGE_FILE);
} finally {
write(fileContents, outputFile);
for (int l = 0; l < totalFile; l++) {
fileDatas[l].delete();
}
}
}
Please show the "inefficient" of this method, once again... only large files that cannot be merge using this method, smaller one ( < 1 GB) no problem at all....
I appreciate if you do not suggest me to increase the heap memory instead show me the fundamental error of this method... thanks...
Thanks
It's unnecessary to allocate the entire file size in memory by declaring a byte array of the entire size. Building the concatenated file in memory in general is totally unnecessary.
Just open up an outputstream for your target file, and then for each file that you are combining to make it, just read each one as an input stream and write the bytes to outputstream, closing each one as you finish. Then when you're done with them all, close the output file. Total memory use will be a few thousand bytes for the buffer.
Also, don't do I/O operations in finally block (except closing and stuff).
Here is a rough example you can play with.
ArrayList<File> files = new ArrayList<>();// put your files here
File output = new File("yourfilename");
BufferedOutputStream boss = null;
try
{
boss = new BufferedOutputStream(new FileOutputStream(output));
for (File file : files)
{
BufferedInputStream bis = null;
try
{
bis = new BufferedInputStream(new FileInputStream(file));
boolean done = false;
while (!done)
{
int data = bis.read();
boss.write(data);
done = data < 0;
}
}
catch (Exception e)
{
//do error handling stuff, log it maybe?
}
finally
{
try
{
bis.close();//do this in a try catch just in case
}
catch (Exception e)
{
//handle this
}
}
}
} catch (Exception e)
{
//handle this
}
finally
{
try
{
boss.close();
}
catch (Exception e) {
//handle this
}
}
... show me the fundamental error of this method
The implementation flaw is that you are creating a byte array (fileContents) whose size is the total file size. If the total file size is too big, that will cause an OOME. Inevitably.
Solution - don't do that! Instead "stream" the file by reading from the "chunk" files and writing to the final file using a modest sized buffer.
There are other problems with your code too. For instance, it could leak file descriptors because you are not ensure that inStream is closed under all circumstances. Read up on the "try-with-resources" construct.
I am trying to write an Applet that established a socket connection with a server and receives FFT data from that server, computes a spectrogram and displays it. Currently, this is what I have in C.
int getData(){
int i;
int constant;
// get as many bytes in the socket to fill up the buffer
n = recv(sockfd, tempBuf + readCount, length - readCount, MSG_DONTWAIT);
if(n>0)
readCount += n;
if(readCount == length) //when get enough data
{
// check header constant
constant = ((int*)(tempBuf))[0];
fprintf(stderr, "\nReading header... ");
printf("header.constSync is %X\n", constant);
if(constant != 0xACFDFFBC)
error1("ERROR reading from socket, incorrect header placement\n");
//put data into a buffer
for( i = 0 ; i < samp_rate; i++)
buffer[i] = ((double*)(tempBuf + sizeof(struct fft_header)))[i];
fprintf(stderr, "Reading data... ");
//shift
shift();
readCount = 0;
}
return 1;
}
However I also wrote a similar method in Java that I am hoping will accomplish the same thing. Is this right?
public int getData() throws IOException {
int constant;
BufferedInputStream data = null;
try{
data=new BufferedInputStream(socket.getInputStream());
} catch (UnknownHostException e){
System.err.println("Invalid Host");
}
catch (IOException e){
System.err.println("Couldn't get the I/O for the connection to the host");
}
int numBytes = data.available();
if(numBytes >0){
readCount+=numBytes;
}
if(readCount == length){
constant = tempBuff[0];
System.out.println("Reading Header");
System.out.println(constant);
if(constant != 0xACFDFFBC){
System.err.println("Error reading from Socket. Incorrect Header Placement");
}
for(int i=0; i<samp_rate; i++){
buffer[i] = tempBuff[i];
System.out.println("Reading data...");
}
}
return 1;
}
**Edit - Sorry I forgot to post the actual question. What I am trying to ask is am I using bufferedInputStream correctly? Or should I use DataInputStream? Also I understand that available() is used to determine how many bytes to read. Am I using it right?
You should know perfectly well that it doesn't work, unless you haven't even bothered to try it, in which case you have no business to be posting here at all yet. There is:
a misuse of available()
an assignment to constant from an undeclared array variable that could be anything
no actual reading going on at all.
You should be using the facilities of DataInputStream for this: readInt(), readDouble(), readFully(), etc. Wrap the BufferedInputStream in a DataInputStream and start calling those methods.
I currently writing a Java TCP server to handle the communication with a client (which I didn't write). When the server, hosted on windows, responds to the client with the number of records received the client doesn't read the integer correctly, and instead reads it as an empty packet. When the same server code, hosted on my Mac, responds to the client with the number of records received the client reads the packet and responds correctly. Through my research I haven't found an explanation that seems to solve the issue. I have tried reversing the bytes (Integer.reverseBytes) before calling the writeInt method and that didn't seem to resolve the issue. Any ideas are appreciated.
Brian
After comparing the pcap files there are no obvious differences in how they are sent. The first byte is sent followed by the last 3. Both systems send the correct number of records.
Yes I'm referring to the DataOutputStream.writeInt() method. //Code added
public void run() {
try {
InputStream in = socket.getInputStream();
DataOutputStream datOut = new DataOutputStream(socket.getOutputStream());
datOut.writeByte(1); //sends correctly and read correctly by client
datOut.flush();
//below is used to read bytes to determine length of message
int bytesRead=0;
int bytesToRead=25;
byte[] input = new byte[bytesToRead];
while (bytesRead < bytesToRead) {
int result = in.read(input, bytesRead, bytesToRead - bytesRead);
if (result == -1) break;
bytesRead += result;
}
try {
inputLine = getHexString(input);
String hexLength = inputLine.substring(46, 50);
System.out.println("hexLength: " + hexLength);
System.out.println(inputLine);
//used to read entire sent message
bytesRead = 0;
bytesToRead = Integer.parseInt(hexLength, 16);
System.out.println("bytes to read " + bytesToRead);
byte[] dataInput = new byte[bytesToRead];
while (bytesRead < bytesToRead) {
int result = in.read(dataInput, bytesRead, bytesToRead - bytesRead);
if (result == -1) break;
bytesRead += result;
}
String data = getHexString(dataInput);
System.out.println(data);
//Sends received data to class to process
ProcessTel dataValues= new ProcessTel(data);
String[] dataArray = new String[10];
dataArray = dataValues.dataArray();
//assigns returned number of records to be written to client
int towrite = Integer.parseInt(dataArray[0].trim());
//Same write method on Windows & Mac...works on Mac but not Windows
datOut.writeInt(towrite);
System.out.println("Returned number of records: " + Integer.parseInt(dataArray[0].trim()) );
datOut.flush();
} catch (Exception ex) {
Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
datOut.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
As described in its Javadoc, DataOutputStream.writeInt() uses network byte order as per the TCP/IP RFCs. Is that the method you are referring to?
No, x86 processors only support little-endian byte order, it doesn't vary with the OS. Something else is wrong.
I suggest using wireshark to capture the stream from a working Mac server and a non-working Windows server and compare.
Some general comments on your code:
int bytesRead=0;
int bytesToRead=25;
byte[] input = new byte[bytesToRead];
while (bytesRead < bytesToRead) {
int result = in.read(input, bytesRead, bytesToRead - bytesRead);
if (result == -1) break;
bytesRead += result;
}
This EOF handling is hokey. It means that you don't know whether or not you've actually read the full 25 bytes. And if you don't, you'll assume that the bytes-to-send is 0.
Worse, you copy-and-paste this code lower down, relying on proper initialization of the same variables. If there's a typo, you'll never know it. You could refactor it into its own method (with tests), or you could call DataInputStream.readFully().
inputLine = getHexString(input);
String hexLength = inputLine.substring(46, 50);
You're converting to hex in order to extract an integer? Why? And more important, if you have any endianness issues this is probably the reason
I was originally going to recommend using a ByteBuffer to extract values, but on a second look I think you should wrap your input stream with a DataInputStream. That would allow you to read complete byte[] buffers without the need for a loop, and it would let you get rid of the byte-to-hex-to-integer conversions: you'd simply call readInt().
But, continuing on:
String[] dataArray = new String[10];
dataArray = dataValues.dataArray();
Do you realize that the new String[10] is being thrown away by the very next line? Is that what you want?
int towrite = Integer.parseInt(dataArray[0].trim());
datOut.writeInt(towrite);
System.out.println("Returned number of records: " + Integer.parseInt(dataArray[0].trim()) );
If you're using logging statements, print what you're actually using (towrite). Don't recalculate it. There's too much of a chance to make a mistake.
} catch (Exception ex) {
Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
}
// ...
} catch (IOException e) {
e.printStackTrace();
}
Do either or both of these catch blocks get invoked? And why do they send their output to different places? For that matter, if you have a logger, why are you inserting System.out.println() statements?
My application loops through about 200 urls that are all jpg images.
In the simulator it reads ok, then stores the byte array in persistentStore with no problems.
On the device, it gives java.io.IOException: TCP read timed out on basically every image.
Every now and then, one gets through. Not even sure how. The image sizes don't give insight either. Some are 6k, some are 11k. Size doesn't seem to matter for timing out.
I'll try to post what I believe to be the relevant code, but I am not really an expert here, so if I left something out, please say so.
Call http connection through loop and join thread:
for(int i = 0; i < images.size(); i ++)
{
try {
String url = images.elementAt(i).toString();
HttpRequest data3 = new HttpRequest(url, "GET", false);
data3.start();
data3.join();
} catch (IOException e) {
Dialog.inform("wtf " + e);
}
}
Make the actual connection in HttpConnection class with the proper suffix:
try
{
HttpConnection connection = (HttpConnection)Connector.open(url + updateConnectionSuffix());
int responseCode = connection.getResponseCode();
if(responseCode != HttpConnection.HTTP_OK)
{
connection.close();
return;
}
String contentType = connection.getHeaderField("Content-type");
long length = connection.getLength();
InputStream responseData = connection.openInputStream();
connection.close();
outputFinal(responseData, contentType, length);
}
catch(IOException ex)
{
} catch (SAXException ex) {
} catch (ParserConfigurationException ex) {
}
Finally, read the stream and write the bytes to a byte array:
else if(contentType.equals("image/png") || contentType.equals("image/jpeg") || contentType.equals("image/gif"))
{
try
{
if((int) length < 1)
length = 15000;
byte[] responseData = new byte[(int) length];
int offset = 0;
int numRead = 0;
StringBuffer rawResponse = new StringBuffer();
int chunk = responseData.length-offset;
if(chunk < 1)
chunk = 1024;
while (offset < length && (numRead=result.read(responseData, offset, chunk)) >= 0){
rawResponse.append(new String(responseData, offset, numRead));
offset += numRead;
}
String resultString = rawResponse.toString();
byte[] dataArray = resultString.getBytes();
result.close();
database db = new database();
db.storeImage(venue_id, dataArray);
}
catch( Exception e )
{
System.out.println(">>>>>>>----------------> total image fail: " + e);
}
}
Things to consider:
Length is always byte length in simulator. In device it is always -1.
The chunk var is a test to see if I force a 15k byte array, will it try to read as expected since byte[-1] gave an out of bounds exception. The results are the same. Sometimes it writes. Mostly it times out.
Any help is appreciated.
You can adjust the length of TCP timeouts on Blackberry using the parameter 'ConnectionTimeout'.
In your code here:
HttpConnection connection = (HttpConnection)Connector.open(url + updateConnectionSuffix());
You'll want to append ConnectionTimeout. You might write it into updateConnectionSuffix() or just append it.
HttpConnection connection = (HttpConnection)Connector.open(url + updateConnectionSuffix() + ";ConnectionTimeout=54321");
This sets the timeout to 54321 milliseconds.
Timeouts occur when the client is waiting for the server to send an ack and it doesn't get one in a specified amount of time.
edit: also, are you able to use the browser and stuff? You may also want to play with the deviceside parameter.
I think the problem may be that you're closing the connection before reading the bytes from the input stream. Try moving the connection.close() after the bytes have been read in.
I have a c++ client which needs to send a file to a c++ server. I'm splitting the file to chunks of PACKET_SIZE (=1024) bytes and send them over a TCP socket. At the server side I read at most PACKET_SIZE bytes to a buffer. When the client sends files which are less than PACKET_SIZE, the server receives more bytes than sent. Even when I limit the number of bytes to be exactly the size of the file, the files differ. I know the problem does not have to do with the client because I've tested it with a c++ server and it works flawlessly.
Thanks.
Server:
public void run() {
DataInputStream input = null;
PrintWriter output = null;
try {
input = new DataInputStream (_client.getInputStream());
}
catch (Exception e) {/* Error handling code */}
FileHeader fh = recvHeader(input);
size = fh._size;
filename = fh._name;
try {
output = new PrintWriter(_client.getOutputStream(), true);
}
catch (Exception e) {/* Error handling code */}
output.write(HEADER_ACK);
output.flush();
FileOutputStream file = null;
try {
file = new FileOutputStream(filename);
}
catch (FileNotFoundException fnfe) {/* Error handling code */}
int total_bytes_rcvd = 0, bytes_rcvd = 0, packets_rcvd = 0;
byte [] buf = new byte [PACKET_DATA_SIZE];
try {
int max = (size > PACKET_DATA_SIZE)? PACKET_DATA_SIZE: size;
bytes_rcvd = input.read(buf,0, max);
while (total_bytes_rcvd < size) {
if (-1 == bytes_rcvd) {...}
++packets_rcvd;
total_bytes_rcvd += bytes_rcvd;
file.write (buf,0, bytes_rcvd);
if (total_bytes_rcvd < size)
bytes_rcvd = input.read(buf);
}
file.close();
}
catch (Exception e) {/* Error handling code */}
}
Client:
char packet [PACKET_SIZE] ;
file.open (filename, ios::in | ios::binary);//fopen (file_path , "rb");
int max = 0;
if (file.is_open()) {
if (size > PACKET_SIZE)
max = PACKET_SIZE;
else
max = size;
file.read (packet , max);
}
else {...}
int sent_packets = 0;
while (sent_packets < (int) ceil (((float)size)/PACKET_SIZE) ) {
_write=send(_sd , packet, max,0);
if (_write <0) {...}
else {
++sent_packets;
if (size > PACKET_SIZE* sent_packets) {
if (size - PACKET_SIZE* sent_packets >= PACKET_SIZE)
max = PACKET_SIZE;
else
max = size - PACKET_SIZE* sent_packets;
file.read (packet , max);
}
}
}
Is the sending socket closed at the end of the file, or is the next file streamed over the same socket? If more than one file is streamed, you could pick up data from the next file if you have the endedness wrong for the file size in recvHeader(), i.e. you send a file of length 0x0102 and try to read one of length 0x0201.
Other question, why do you provide a max for the first read, but not for the following reads on the same file?
One issue I see is that it appears that you assume that if the send returns a non-error, that it sent the entire chunk you requested it to send. This is not necessarily true, especially with stream sockets. How large are the packets you are sending, and how many? The most likely reason this could occur would be if the sndbuf for the socket filled, and your socket _sd is set to non-blocking. I'm not positive (depends on stack implementation), but I believe it could also likely occur if the TCP transmit window was full for your connection, and tcp couldn't enqueue your entire packet.
You should probably loop on the send until max is sent.
Thusly:
int send_ct=0;
while( (_write = send(_sd, packet + send_ct, max-send_ct, 0)) > 0) {
send_ct += _write;
if(send_ct >= max) {
break;
} else {
// Had to do another send
}
}
the code is not complete. E.g. you have omitted the sending of the filename and the filesize, as well as the parsing of those values. Are those values correct? If not first ensure that these values are the right ones before investigating further.