2013-04-01 99 views
3

我有一個運行在java中的「服務器」,我通過字節數組發送文件到「客戶端」(android系統)。該功能工作正常,但我注意到當我嘗試發送更大的文件(1MB +)時,在關閉之前它沒有成功寫入所有字節(例如:試圖發送5MB,並且它只發送902字節)。有沒有辦法讓代碼在關閉流之前等待流完成寫入?以下是代碼和堆棧跟蹤。實質上,發送消息方法在附加和發送文件時(在處理GUI的類中)被調用。在這種情況下,我沒有試圖從客戶端接收數據,只是發送數據到客戶端。Java - 等待流完成寫入?

編輯:我知道我現在只有字節數組設置爲1MB。我有它在5MB,它仍然只寫1MB的<。即使在1MB,它仍然只寫902字節。

EDIT2:我已經發布了一些處理接收數據的CLIENT端的代碼。

public void sendMessage(File file) { 
    if(mOut != null) { 
     try { 
      FileInputStream inStream = new FileInputStream(file);    
      byte[] message = new byte[1024 * 1024]; 
      inStream.read(message); 
      mOut.write(message, 0, message.length); 
      mOut.flush(); 
      inStream.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

public void run() { 
    super.run(); 
    running = true; 
    try { 
     System.out.println("S: Connecting..."); 
     ServerSocket serverSocket = new ServerSocket(SERVERPORT); 
     Socket client = serverSocket.accept(); 
     linked = true; 
     System.out.println("S: Receiving..."); 

     try { 
      mOut =client.getOutputStream(); 
      InputStream in = client.getInputStream(); 
      while(running) { 
       byte[] message = new byte[1024 * 1024]; 
       in.read(message); 
       if(message != null && messageListener != null) { 
        messageListener.messageReceived(message); 
       } 
      } 
     } catch (Exception ex) { 
      System.out.println("S:Error"); 
      ex.printStackTrace(); 
     } finally { 
      client.close(); 
      System.out.println("S:Done"); 
     } 
    } catch (Exception ex) { 
     System.out.println("S: Error"); 
     ex.printStackTrace(); 
    } 

} 
--------------------------------------------------------------------------- 
java.net.SocketException: Connection reset by peer: socket write error 
at java.net.SocketOutputStream.socketWrite0(Native Method) 
at java.net.SocketOutputStream.socketWrite(Unknown Source) 
at java.net.SocketOutputStream.write(Unknown Source) 
at Server.sendMessage(Server.java:34) 
at ServerBoard$2.actionPerformed(ServerBoard.java:57) 
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) 
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) 
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) 
at javax.swing.DefaultButtonModel.setPressed(Unknown Source) 
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) 
at java.awt.Component.processMouseEvent(Unknown Source) 
at javax.swing.JComponent.processMouseEvent(Unknown Source) 
at java.awt.Component.processEvent(Unknown Source) 
at java.awt.Container.processEvent(Unknown Source) 
at java.awt.Component.dispatchEventImpl(Unknown Source) 
at java.awt.Container.dispatchEventImpl(Unknown Source) 
at java.awt.Component.dispatchEvent(Unknown Source) 
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) 
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) 
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) 
at java.awt.Container.dispatchEventImpl(Unknown Source) 
at java.awt.Window.dispatchEventImpl(Unknown Source) 
at java.awt.Component.dispatchEvent(Unknown Source) 
at java.awt.EventQueue.dispatchEventImpl(Unknown Source) 
at java.awt.EventQueue.access$000(Unknown Source) 
at java.awt.EventQueue$3.run(Unknown Source) 
at java.awt.EventQueue$3.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) 
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) 
at java.awt.EventQueue$4.run(Unknown Source) 
at java.awt.EventQueue$4.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) 
at java.awt.EventQueue.dispatchEvent(Unknown Source) 
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) 
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) 
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) 
at java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
at java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
at java.awt.EventDispatchThread.run(Unknown Source) 
java.net.SocketException: Connection reset 
at java.net.SocketInputStream.read(Unknown Source) 
at java.net.SocketInputStream.read(Unknown Source) 
at java.net.SocketInputStream.read(Unknown Source) 
at Server.run(Server.java:58) 

這是客戶端的代碼片段。

public void run() { 
    mRun = true; 
    serverMessage = new byte[1024 * 1024]; 
    try { 
     InetAddress serverAddr = InetAddress.getByName(SERVERIP); 
     Log.e("TCP Client", "C:Connecting..."); 
     Socket socket = new Socket(serverAddr, SERVERPORT); 
     try { 
      in = socket.getInputStream(); 
      while(mRun) { 
       in.read(serverMessage); 
       if(serverMessage != null && mMessageListener != null) { 
        mMessageListener.messageReceived(new String(serverMessage)); 
      } 
       serverMessage = null; 
      } 

      Log.e("RESPONSE FROM SERVER","S:Received Message: '" + serverMessage + "'"); 

     } catch(Exception ex) { 
      Log.e("TCP","S: Error", ex); 
     } finally { 
      socket.close(); 
     } 
    } catch(Exception ex) { 
     Log.e("TCP","C: Error", ex); 
    } 
} 
+0

當字節緩衝區大小隻有1MB時,不能寫入大於1MB的文件。您正在填充緩衝區,寫入並關閉輸出流。也許嘗試使用BufferedReader和循環代替 – HXCaine

+0

啊,是的,我確實改變了它,看看我能寫的最大值是多少。我擁有5MB的容量,而且還沒有寫完整件事。即使使用1MB,它也只能寫入902個字節。 – kaptaincooke

+0

您的while循環運行多次? – HXCaine

回答

1

首先,read的JavaDoc:

讀取從輸入流的字節,並將它們存儲一些數成 緩衝區數組b中。實際讀取的字節數作爲整數返回爲 。此方法阻塞,直到輸入數據可用,檢測到文件末尾 或引發異常。

由於源是一個套接字,即使緩衝區大小爲1 MByte,返回的字節數也可能會比預期的要少,因此返回的902 KB字節正常。你必須循環直到流結束。

下面的方法讀取所有字節,比通話監聽:

byte[] message = new byte[0]; 
byte[] buffer = new byte[4096]; 
int len; 
while((len = is.read(buffer)) > -1) { 
    byte[] tmp = new byte[message.length+len]; 
    System.arraycopy(message, 0, tmp, 0, message.length); 
    System.arraycopy(buffer , 0, tmp, message.length, len); 
    message = tmp; 
} 
messageListener.messageReceived(message); 

正如你所看到的,很多再分配的發生:你必須重新設計你的協議先發送文件的大小和分配一次接收緩衝區。

+0

雖然我並不想接收任何數據,但我不明白如何讀取和接收字節是問題? – kaptaincooke

+0

「重置對等」,原因是在另一邊。張貼另一面的代碼。 – Aubin

+0

使用客戶端的代碼編輯。 – kaptaincooke

1

你讀緩衝區設置爲空讀完前:

in = socket.getInputStream(); 
while(mRun) { 
    in.read(serverMessage); 
    if(serverMessage != null && mMessageListener != null) { 
     mMessageListener.messageReceived(new String(serverMessage)); 
    } 
    serverMessage = null; 
} 

這將導致一個NullPointerException,你的代碼將關閉套接字。