0

So i am building a program which needs an auto-updating feature built in to it, as i was finished up and tested it out, it seems when i send the jar file over the socket and write it to the newly made jar file it is missing 5KB (everytime... even when the size changes) size from it and becomes corrupt.

Here is my code:

package server.update;

import java.io.*;
import java.net.Socket;

public class UpdateThread extends Thread
{
BufferedInputStream input; //not used
BufferedInputStream fileInput;
BufferedOutputStream output;

public UpdateThread(Socket client) throws IOException
{
    super("UpdateThread");
    output = new BufferedOutputStream(client.getOutputStream());
    input = new BufferedInputStream(client.getInputStream());
}

public void run()
{
    try
    {
        File perm = new File(System.getProperty("user.dir")+"/GameClient.jar");
        //fileInput = new BufferedInputStream(new FileInputStream(perm));
        fileInput = new BufferedInputStream(new FileInputStream(perm));

        byte[] buffer = new byte[1024];
        int numRead;
        while((numRead = fileInput.read(buffer)) != -1)
            output.write(buffer, 0, numRead);

        fileInput.close();
        input.close();
        output.close();
        this.interrupt();
    }
    catch(Exception e)
    {e.printStackTrace();}
}
}

This is the class that will wait for a connection from the client and then push the update to them as soon as it connects. File Perm is the jar file that i want to send over and for whatever reason it seems to either miss the last 5 bytes or the client doesn't read the last 5 (i don't know which). Here is the client's class of receiving the information here:

public void getUpdate(String ip) throws UnknownHostException, IOException
{
    System.out.println("Connecting to update socket");
    update = new Socket(ip,10004);
    BufferedInputStream is = new BufferedInputStream(update.getInputStream());
    BufferedOutputStream os = new BufferedOutputStream(update.getOutputStream());

    System.out.println("Cleaning GameClient.jar file");
    File updated = new File(System.getProperty("user.dir")+"/GameClient.jar");
    if(updated.exists())
        updated.delete();
    updated.createNewFile();

    BufferedOutputStream osf = new BufferedOutputStream(new FileOutputStream(updated));

    System.out.println("Writing to GameClient.jar");
    byte[] buffer = new byte[1024];
    int numRead = 0;
    while((numRead = is.read(buffer)) != -1)
        osf.write(buffer, 0, numRead);

    System.out.println("Finished updating...");
    is.close();
    os.close();
    update.close();
    osf.close();
}

Any help is appreciated. Thanks!

3kings
  • 838
  • 2
  • 13
  • 28
  • In almost all languages, on all platforms you are required to call a .Flush method prior to .Close to ensure the last remnants are pushed (to disk or to the network). For some reason .Close never calls .Flush. – MDR Nov 16 '13 at 23:10
  • 1
    @MDR Untrue. See the contract for FilterOutputStream.close(). In any well designed class library, close should ensure flushing. – user207421 Nov 17 '13 at 02:54

3 Answers3

2

You have too many closes. Remove update.close() and is.close(). These both close the socket, which prevents the buffered stream 'osf' from being auto-flushed when closed. Closing either the input stream or the output stream or a socket closes the other stream and the socket. You should therefore only close the outermost output stream you have wrapped around the socket, in this case osf, and maybe the socket itself in a finally block to be sure.

user207421
  • 305,947
  • 44
  • 307
  • 483
0

Thanks to MDR for the answer, it worked!!

I had to change the following lines of code in the UpdateThread class:

Before:

fileInput.close();
input.close();
output.close();
this.interrupt();

After:

fileInput.close();
output.flush();
output.close();
input.close();
this.interrupt();

You must flush the stream before closing, also i switched the order because if you closed the inputstream attached to the socket it will close the socket and then will not move on to closing the outputstream or flushing it.

Thanks again!

3kings
  • 838
  • 2
  • 13
  • 28
  • That was not the problem. The problem was all the extra closes, also including 'update.close()', which you haven't included in your quoted code. You don't have to flush a stream before closing: it happens automatically. – user207421 Nov 17 '13 at 02:57
-2

Have you considered using an http library to delegate all of the connection handling and reading/writing to known working code? You're reinventing a lot of wheels here. Additionally at some point you're going to want to ensure the content you're receiving is authentic and undamaged (you're doing that by loading the class, which is somewhat dangerous, especially when you're exchanging data in cleartext!) Again, using a library and its methods would allow you to choose HTTPS, allowing TLS to do much of your work.

I'd also suggest that your server tell the client some metadata in advance, regardless- perhaps the content length and possibly a hash or checksum so the client can detect failures in the transfer.

This question seems to have answers relevant to your situation as well. Good luck!

Community
  • 1
  • 1
  • That has no bearing on the channel you employ to distribute code. – bizzyunderscore Nov 16 '13 at 23:29
  • 1
    I don't see how this is an Answer to the Question asked. The OP does not need to use HTTP. While he might need some of those things (checking that content is undamaged and comes from an authentic source) there are other ways to implement them. Besides, those concerns are orthogonal to the Question ... if you look at what the real Answer was/is. – Stephen C Nov 16 '13 at 23:41
  • There are certainly other ways to implement every aspect of his question. The OP doesn't need to use IP either; but doing so will likely improve the quality of his life. His fundamental question was how to avoid an integrity problem when transferring code over a network link and my answer absolutely did address it. – bizzyunderscore Nov 17 '13 at 00:09
  • 1
    No it doesn't. His fundamental question is about a specific bug in his code. His equivalent code using HTTP is likely to have exactly the same bug in it. Changing to HTTP would NOT solve his problem. Look are the other answers!! – Stephen C Nov 17 '13 at 02:59
  • I can't recall the last time I was required to call flush or close on an http library method; but I will concede that you are most certainly correct and I am wrong. – bizzyunderscore Nov 17 '13 at 03:10
  • 1
    @StephenC hasn't said anything about calling `flush()` before `close()`. The OP and MDR are both wrong about that. – user207421 Nov 17 '13 at 04:34