简体   繁体   中英

Jar File is corrupt after sending over socket

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!

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.

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!

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM