2014-12-07 2 views
0

Я пытаюсь отправить файл с сервера с помощью java-селекторного ключа NIO, но с клиентской стороны я получаю весь файл при закрытии сервера.отправить файл с помощью java NIO selector

Код для серверной части

public static int DEFAULT_PORT = 1234; 

public static void main(String[] args) { 
    String fileName = "10mb.txt"; 
    int port; 

    try { 
     port = Integer.parseInt(args[0]); 
    } catch (Exception ex) { 
     port = DEFAULT_PORT; 
    } 
    System.out.println("Listening for connections on port " + port); 

    ServerSocketChannel serverChannel; 
    Selector selector; 
    try { 
     serverChannel = ServerSocketChannel.open(); 
     ServerSocket ss = serverChannel.socket(); 
     InetSocketAddress address = new InetSocketAddress(port); 
     ss.bind(address); 
     serverChannel.configureBlocking(false); 
     selector = Selector.open(); 
     serverChannel.register(selector, SelectionKey.OP_ACCEPT); 
    } catch (IOException ex) { 
     ex.printStackTrace(); 
     return; 
    } 

    while (true) { 

     try { 
      selector.select(); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
      break; 
     } 

     Set readyKeys = selector.selectedKeys(); 
     Iterator iterator = readyKeys.iterator(); 
     while (iterator.hasNext()) { 

      SelectionKey key = (SelectionKey) iterator.next(); 

      try { 

       if (key.isAcceptable()) { 
        ServerSocketChannel server = (ServerSocketChannel) key.channel(); 
        SocketChannel client = server.accept(); 
        System.out.println("Accepted connection from " + client); 
        client.configureBlocking(false); 
        SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE); 

        String filePath = (fileName); 
        File file = new File(filePath); 
        int fileSize = (int) file.length(); 
        System.out.println("File size =" + fileSize); 
        FileInputStream fis; 
        ByteBuffer buffer = null; 

        try { 
         fis = new FileInputStream(file); 
         FileChannel fc = fis.getChannel(); 
         buffer = ByteBuffer.allocate(fileSize); 
         try { 
          fc.read(buffer); 
         } catch (IOException ex) { 
          System.out.println("IO EX :" + ex); 
         } 
        } catch (FileNotFoundException ex) { 
         System.out.println("FileNotFoundEx :" + ex); 
        } 

        buffer.flip(); 
        key2.attach(buffer); 

       } else if (key.isWritable()) { 

        SocketChannel client = (SocketChannel) key.channel(); 
        ByteBuffer out = (ByteBuffer) key.attachment(); 

        client.write(out); 
       } 

      } catch (IOException ex) { 
       System.out.println("IO Exeption :" + ex); 
       key.cancel(); 
       try { 
        key.channel().close(); 
       } catch (IOException cex) { 
        System.out.println(cex); 
       } 
      } 
      iterator.remove(); 

     } 

    } 

} 

Код для клиентской стороны

public static void main(String[] args) throws IOException { 
    String fileName = "10mb.txt"; 
    int bufferSize = 2048; 
    int n = 0; 
    int read = 0; 

    SocketChannel socket = SocketChannel.open(new InetSocketAddress(1234)); 
    String filePath = (fileName); 

    FileOutputStream out = new FileOutputStream(filePath); 
    FileChannel file = out.getChannel(); 
    ByteBuffer buffer = ByteBuffer.allocate(bufferSize); 

    long startTime = System.currentTimeMillis(); 


    while ((read = socket.read(buffer)) > 0) { 
     buffer.flip(); 

     file.write(buffer); 

     n = n + read; 

     buffer.clear(); 

     System.out.println(n); 
    } 
    long endTime = System.currentTimeMillis(); 
    long difference = endTime - startTime; 
    System.out.println("File with " + n + " bytes downloaded in " + difference + " ms"); 
    socket.close(); 

    file.close(); 

    out.close(); 
} 

Я ценит вашу помощь.

ответ

1

Вы предполагаете, что fc.read() заполняет буфер и что sc.write() пустёт его. Ни одно предположение не является допустимым. Правильный способ для копирования между каналами в Java заключается в следующем:

while (in.read(buffer) > 0 || buffer.position() > 0) 
{ 
    buffer.flip(); 
    out.write(buffer); 
    buffer.compact(); 
} 

Как вы выводите на SocketChannel в режиме неблокирующих вам нужно будет изменить это для случая, когда write() возвращает ноль: если это произойдет , вам необходимо зарегистрировать канал для OP_WRITE, вернуться к циклу select() и возобновить этот цикл при запуске OP_WRITE: на этот раз, если write() возвращает ненулевое значение, отменяет регистрацию OP_WRITE.

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