2013-11-16 3 views
0

Итак, я создаю программу, для которой требуется встроенная функция автоматического обновления, поскольку я был закончен и протестирован, кажется, когда я отправляю файл jar через сокет и записать его в недавно созданный файл jar, он пропускает 5 КБ (каждый раз ... даже когда размер изменяет) размер от него и становится коррумпированным.Jar File поврежден после отправки через сокет

Вот мой код:

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();} 
} 
} 

Это класс, который будет ждать подключения от клиента, а затем нажмите обновления к ним, как только он соединяет. Файл Perm - это файл jar, который я хочу отправить, и по какой-либо причине он либо пропускает последние 5 байтов, либо клиент не читает последние 5 (я не знаю, какой). Вот класс клиента для получения информации здесь:

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(); 
} 

Любая помощь приветствуется. Благодаря!

+0

Практически во всех языках на всех платформах вам необходимо вызвать метод .Flush до .Close, чтобы обеспечить оставление последних остатков (на диск или в сеть). По какой-то причине .Close никогда не вызывает .Flush. – MDR

+0

Спасибо, что это сработало – 3kings

+1

@MDR Неверно. См. Контракт для FilterOutputStream.close().В любой хорошо разработанной библиотеке классов закрытие должно обеспечивать промывку. – EJP

ответ

2

У вас слишком много закрытий. Удалить update.close() и is.close(). Они оба закрывают розетку, что предотвращает автоматическое сбрасывание буферизованного потока «osf» при закрытии. Закрытие входного потока или выходного потока или сокета закрывает другой поток и сокет. Поэтому вы должны закрыть только внешний выходной поток, который вы обернули вокруг сокета, в этом случае osf, и, возможно, сам сокет в блоке finally, чтобы быть уверенным.

-2

Рассматривали ли вы использование http library для делегирования всей обработки соединений и чтения/записи в известный рабочий код? Вы изобретаете много колес здесь. Кроме того, в какой-то момент вам захочется убедиться, что контент, который вы получаете, является подлинным и неповрежденным (вы делаете это, загружая класс, что несколько опасно, особенно когда вы обмениваетесь данными в открытом виде!) Снова , используя библиотеку и ее методы позволят вам выбрать HTTPS, позволяя TLS выполнять большую часть вашей работы.

Я также предлагаю, чтобы ваш сервер сообщал клиенту некоторые метаданные заранее, независимо от длины содержимого и, возможно, хэша или контрольной суммы, чтобы клиент мог обнаружить сбои в передаче.

This question, похоже, есть ответы, относящиеся к вашей ситуации. Удачи!

+0

Это не игра на основе http, ее клиентский сервер. – 3kings

+0

Это не влияет на канал, который вы используете для распространения кода. – bizzyunderscore

+1

Я не вижу, как это ответ на заданный вопрос. OP не нужно использовать HTTP. Хотя ему могут понадобиться некоторые из этих вещей (проверка того, что контент не поврежден и исходит от подлинного источника), существуют и другие способы их реализации. Кроме того, эти проблемы ортогональны Вопросу ... если вы посмотрите, какой был настоящий ответ. –

0

Благодаря MDR для ответа, это сработало!

я должен был изменить следующие строки кода в классе UpdateThread:

До:

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

После:

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

Вы должны промыть поток перед закрытием, и я переключился, потому что, если вы закрыли входной канал, подключенный к сокету, он закроет сокет, а затем не будет двигаться к закрытию выходного потока или его промывке.

Еще раз спасибо!

+0

Это не проблема. Проблема заключалась в дополнительном закрытии, в том числе «update.close()», который вы не включили в свой котировочный код. Вам не нужно очищать поток до закрытия: это происходит автоматически. – EJP

Смежные вопросы