2013-10-28 3 views
0

Я разрабатываю простую программу для переноса файлов между клиентом и сервером. Вот мой код: Мой клиент (Sender):EOFException или SocketException: Socket закрыт, когда файл передачи через сокет

try{ 
       File file_sender=XMLParser.register(peername, address, port, listfile); 
       int count; 
       byte[] buffer = new byte[1024]; 
       int len=(int) file_sender.length(); 
       byte[] mybytearray = new byte[len];  
       DataOutputStream output=new DataOutputStream(Info.connection.getOutputStream()); 
       output.writeInt(len); 
       System.out.println(len); 
       BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file_sender)); 
       bis.read(mybytearray, 0, len); 
       output.write(mybytearray, 0, len); 
       bis.close(); 
       output.close(); 
       // Info.connection.close(); 
      }catch(Exception ex){ 
       System.out.println(ex.toString()); 
      } 

Мой сервер (приемник):

public class IOThread extends Thread { 
private Socket connection; 
private DataInputStream input; 
public IOThread(Socket connection) throws IOException{ 
    this.connection=connection; 
    input=new DataInputStream(connection.getInputStream()); 

} 
@Override 
public void run(){ 
    while(true){ 
     try{ 
      int filesize=12022386; 
      int bytesRead; 
      int currentTot = 0; 
      byte[] bytearray = new byte [filesize]; 
      int len=input.readInt(); 
      FileOutputStream fos = new FileOutputStream("data.xml"); 
      BufferedOutputStream bos = new BufferedOutputStream(fos); 
      bytesRead=input.read(bytearray, 0,bytearray.length); 
      System.out.println(len); 
      currentTot=bytesRead; 
      do{ 
       bytesRead=input.read(bytearray, currentTot, (bytearray.length-currentTot)); 
       if(bytesRead>=0) currentTot+=bytesRead; 
       System.out.println("pos: "+currentTot); 
      } while(len!=currentTot); 
      bos.write(bytearray, 0, currentTot); 
      bos.close(); 
      //connection.close(); 
      System.out.println("Done"); 
     }catch(EOFException ex){ 
      System.out.println(ex.toString()); 
      break; 
     }catch(Exception ex){} 
    } 
} 

Я хочу Tranfer более одного файла, так что я не хочу закрыть розетку. Таким образом, я использую переменную «len», чтобы проверить, что файл полностью переведен.

Если я закрываю «вывод» после отправки файла, тогда сервер thows EOFException и файл отправляется успешно.

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

Помогите решить эту проблему? Update: Вот мой вывод на экран консоли, если я не закрываю переменную "выход" на клиенте:

Pos: 496

Спасибо. Извините за мой плохой английский

+0

Как именно сервер не получает файл успешно, если вы не закрываете сокет? Застрял ли он в цикле? –

+0

Ваше имя неверное. EOFException и «socket is closed» - это два отдельных условия, а не один. – EJP

ответ

0

Ваше заполнение BufferedOutputStream кажется неправильным. Ниже код должен находиться внутри цикла while.

bos.write(bytearray, 0, currentTot); 

Попробуйте что-нибудь подобное вместо этого:

BufferedOutputStream buffOut=new BufferedOutputStream(fos); 
byte []arr = new byte [1024 * 1024]; 
int available = -1; 
while((available = buffIn.read(arr)) != -1) { 
    buffOut.write(arr, 0, available); 
}  
buffOut.flush(); 
buffOut.close(); 

И тест снова.

Редактировать: Обновлен мой ответ с правильным комментарием Джейсона.

+0

Вы должны проверить '> = 0', а не'> 0', поскольку 0 является допустимым возвращаемым значением для 'read' и не указывает конец ввода (это указывает, что в настоящий момент данных нет и базовый поток будет блокировать, что в основном означает «повторите попытку позже»). –

+0

Я отредактировал мой код, следуя инструкциям. Но строка «Готово» не отображается на экране консоли на сервере, что означает, что она не может выйти из цикла while. – user1956702

+0

@JasonC Это неверно. InputStream.read() возвращает только нуль, если указанная длина равна нулю, что является ошибкой программирования. Если данных нет, они блокируются. Ноль не означает «повторите попытку позже». – EJP

2

Две вещи:

Прежде всего, вы, кажется, не обращая внимания на длину файла в вашем приемном коде? У вас есть:

 int filesize=12022386; 
     int bytesRead; 
     int currentTot = 0; 
     byte[] bytearray = new byte [filesize]; 
     int len=input.readInt(); 

Вы проклейки ByteArray до 12022386 байт, независимо от значения len, и вы просите, что многие байт из входного потока.

Во-вторых, когда вы закрываете выходной поток, любые кэшированные/буферизованные данные, которые еще не были записаны, автоматически очищаются (то есть в вашем случае отправляются на сервер).

Промыть выходной поток явно, когда вы закончите отправку первого файла, чтобы он завершил отправку всех данных на сервер. Затем вы можете продолжать использовать этот выходной поток для других целей.

Сделайте output.flush() в вашем отправляемом коде, когда передача будет завершена.

+0

Я добавил output.flush() после отправки файла на клиенте, но сервер по-прежнему не может получить его успешно. – user1956702

+1

Смотрите мой комментарий re: 'filesize'. Вместо этого используйте значение «len». Ваш вызов 'read' может блокировать попытку чтения 12022386 байт. Кроме того, согласно вашему выходу, вы читаете немного больше, чем длина файла (длина файла 246, но вы читаете не менее 496). –

+0

huhuhuhuhuhuhuhu, Спасибо вам очень очень и очень очень. Stackoverflow является greate. – user1956702

2

Проблема в том, что вы читаете за пределами размера вашего файла, то есть вместо чтения len байтов, вы читаете bytearray.length байт, что больше.

Следовательно, вы читали больше, чем len байт, поэтому len!=currentTot никогда не выполняется, потому что, как вы можете видеть из вашего выхода образца, currentTot == 496 и len == 246.

Внести следующие изменения в ваше время цикла:

do{ 
    bytesRead=input.read(bytearray, currentTot, (len - currentTot)); 
    if(bytesRead>=0) currentTot += bytesRead; 
    System.out.println("pos: " + currentTot); 
} while(len != currentTot); 

Просто, чтобы убедиться, что вы не до конца в бесконечном цикле из-за подобную ошибку, вы можете использовать currentTot < len вместо len != currentTot в качестве условия ,

Кроме того, поскольку вы уже используете DataInputStream, рассмотрите возможность чтения содержимого сокета с помощью readFully. Это блокирует до тех пор, пока определенное количество байтов не будет считано из сокета, что существенно избавит вас от необходимости цикла while. Подробнее here.

+0

точно, я понял. Огромное спасибо. – user1956702

2

Выбросьте все петли и используйте DataInputStream.readFully(); закройте сокет после отправки файла; не заканчивать длину файла; и использовать буфер нормального размера, скажем, 8192 байта.

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