2011-10-07 1 views
1

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

Я фактически делаю демон сервера, который принимает запросы клиентов, а затем он (сервер) передает все файлы, содержащиеся в определенной папке. Я собираюсь опубликовать код sendFileData (на сервере) и getFileData (на клиенте).

Сервер использует:

public static void sendFileData(File file, Socket socket) throws FileNotFoundException, IOException, SocketException { 
    byte[] auxiliar = new byte[8192]; 
    byte[] mybytearray = new byte[(int) file.length()]; 
    int longitud = mybytearray.length; 

    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); 
    bis.read(mybytearray, 0, longitud); 
    DataOutputStream os = new DataOutputStream(socket.getOutputStream()); 
    int paquetes = longitud/8187; 
    int resto = longitud % 8187; 
    int i = 0; 
    while(i<paquetes){//The length goes on the first 4 bytes and the 5th tells if there are more packets to send (8192 bytes or less). 
     byte[] bytes = ByteBuffer.allocate(4).putInt(8187).array(); 
     auxiliar[0] = bytes[0]; 
     auxiliar[1] = bytes[1]; 
     auxiliar[2] = bytes[2]; 
     auxiliar[3] = bytes[3]; 
     auxiliar[4] = 1; 
     for(int j = 5; j < 8192; j++){ 
      auxiliar[j] = mybytearray[i*8187+(j-5)]; 
     } 
     os.write(auxiliar, 0, 8192); 

     i+=1; 
    } 
    if(resto > 0){ 
     byte[] bytes = ByteBuffer.allocate(4).putInt(resto).array(); 
     auxiliar[0] = bytes[0]; 
     auxiliar[1] = bytes[1]; 
     auxiliar[2] = bytes[2]; 
     auxiliar[3] = bytes[3]; 
     auxiliar[4] = 0; 
     for(int j = 5; j < resto+5; j++){ 
      auxiliar[j] = mybytearray[i*8187+(j-5)]; 
     } 
     os.write(auxiliar, 0, resto+5); 
    } 
    os.flush(); 
} 

И в стороне клиента:

public static void receiveFileData(String nombreFichero, Socket s) throws IOException{ 
     File monitored = new File(nombreFichero); 
     if(monitored.exists() == false){ 
      monitored.createNewFile(); 
     } 
     byte[] mybytearray; 
     DataInputStream is = new DataInputStream(s.getInputStream()); 
     FileOutputStream fos = new FileOutputStream(monitored); 
     BufferedOutputStream bos = new BufferedOutputStream(fos); 
     int bytesRead = 0; 
     int hasNext = 1; 
     do { 
      bytesRead = is.readInt();//Leo longitud 
      try { 
       Thread.sleep(1);// HERE!!!! 
      } catch (InterruptedException e) { 
      } 
//   System.out.println("Bytes read "+bytesRead); 
      if(bytesRead <= 8187 && bytesRead > 0){ 
//    System.out.println("Bytes leídos "+bytesRead); 
       hasNext = is.readByte();//Leo si hay más datos por enviar 
       mybytearray = new byte[bytesRead]; 
       is.read(mybytearray); 
       if(monitored.exists()){ 
        synchronized(monitored){ 
         bos.write(mybytearray, 0, mybytearray.length); 
        } 
       } 
       mybytearray = null; 
      }else{ 
       System.out.println("Fuera de rango "+bytesRead); 
      } 
     }while(hasNext == 1); 
     bos.close(); 
     mybytearray = null; 
     System.out.println("Fichero recibido: "+monitored.getAbsolutePath()); 

    } 

В коде receiveFileData, если я не поставить Thread.sleep (1) или System.out .println() или все, что требует времени для выполнения, я не получаю данные на правильном пути на клиенте, потому что readInt() возвращает очень высокое число случайным образом отрицательным или положительным (что подразумевает нехватку памяти и другие исключения) ,

Уверен, что это что-то о синхронизации, но я думаю, что схема переноса между двумя методами правильная (возможно, клиент слишком медленный и сервер слишком быстро).

Что происходит ??? Потому что я не хочу ставить Thread.sleep, я думаю, это нехорошее программирование.

Большое вам спасибо!

+0

Сколько различных потоков потенциально может вызвать getFileData()? Тот же вопрос для sendFileData() ... Кроме того, если вы просто делаете File -> File transfer ... почему даже возиться с чем-либо, кроме байта []? Вам понадобится один int перед загрузкой данных, чтобы сообщить другой стороне, сколько байтов ожидать, но кроме этого просто отправьте сырые байты! – claymore1977

+0

На сервере есть только один поток, который слушает новые подключения (accept()). Когда клиент пытается подключиться к серверу, сервер создает новый поток, который будет управлять отдельно потоками данных между клиентом и сервером, и после этого он продолжает слушать. Клиентская сторона имеет только один поток. Я думаю, что я пытался отправить полный буфер со всеми байтами файла, но я думаю, что это разбилось (я должен проверить, потому что меня сейчас нет дома). Спасибо за ваш ответ – cabreracanal

+0

И этот код передает полный файл, неизменный, из одного места в другое? – claymore1977

ответ

1

is.read (байты) не гарантированно заполняет предоставленный массив байтов. Вам нужно проверить его возвращаемое значение, чтобы узнать, сколько байтов было прочитано или (лучше) использовать readFully().

Сон(), вероятно, просто позволяет время для всех байтов, которые были возвращены из сокета.

+0

О, Большое вам спасибо, я проверю это в понедельник, и если все будет хорошо, я проверю ваш ответ как принятый! – cabreracanal

+0

Спасибо вам большое! readFully было решением, но у меня также есть что-то неправильное в отправителе: когда длина файла% 8187 == 0, для последнего пакета hasNext = 1, и это должно быть 0. Теперь все работает нормально! – cabreracanal