2016-08-11 84 views
0

我正在嘗試將apk文件從一個設備發送到另一個設備。基本上,要發送的用戶具有已安裝的應用程序(非系統應用程序)的gridview,並且當用戶按下其中一個應用程序的圖標時,它會將其發送到其他設備。該文件被緩衝成較小的數據包。BufferInputStream不讀取最後一個數據包

我正在做一些系統來檢查發生了什麼,並且發送設備正在發送X個數據包,同時接收方接收的數據包少於X個數據包(它依賴於正在發送的應用程序,所以這就是爲什麼我寫X )。我認爲這是最後一次失蹤。

我的緩衝區的長度是4096,「最後一個數據包」只有2115個。在接收端,它不會拋出讀寫文件後出現的系統信息。所以程序在閱讀指令時被卡住了。 我的問題是爲什麼最後一個數據包沒有被傳輸?

這是我的代碼。

客戶端 - apk的發送者。

 public class SendThread implements Runnable{ 

    @Override 
    public void run() { 
     try { 

      if(clientSocket==null){ 
       clientSocket=new Socket(serverIP,porto); 
       System.out.println("client comm - Created the client socket.."); 
      } 

      System.out.println(" client comm, i am here in the send thread, going to create the outputstream object"); 
      if(out==null){ 
       out = new ObjectOutputStream(clientSocket.getOutputStream()); 
       System.out.println(" Client COMM SEND THREAD - JUST created the outputstream ."); 
      } 


      File apkToSend=new File(filePath); 
      byte[] buffer = new byte [4096]; 
      BufferedInputStream bis=new BufferedInputStream(new FileInputStream(apkToSend)); 
      int count; 
      int total=0; 
      while((count=bis.read(buffer,0,4096))!=-1){ 
       try { 
        Thread.sleep(200); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       out.write(buffer,0,count); 
       total+=count; 
       out.flush(); 
       System.out.println("Client Comm send thread - already sent this ammount : "+total); 
      } 

      bis.close(); 
      out.flush(); 
      System.out.println("clientComm send thread - Just sent the message ! i am after the out.writeOBject. Not saving it to a string yet."); 


     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

現在在服務器端 - 接收文件的設備..

public class ReceiveThread implements Runnable{ 

    @Override 
    public void run() { 
     try { 
      if(socket==null){ 
       socket=serverSocket.accept(); 
       System.out.println("serverComm - accepted the socket from the client."); 
       out=new ObjectOutputStream(socket.getOutputStream()); 
       out.writeObject("Hello client, i the server, sending you this message because i want to. SO that you unlock from the input stream creation"); 
       System.out.println("SErverComm Created the output stream and sent a HEllo message to the client "); 
      } 

      if(in==null){ 
       in = new ObjectInputStream(socket.getInputStream()); 

      } 
      while(!serverSocket.isClosed()){ 
       try { 
        if(!handshakeDone){ 
         System.out.println("server comm receive thread - INSIDE THE WHILE CICLE, before the in.readObject"); 
         String message = (String) in.readObject(); 
         System.out.println("ServercomM receive thread - just did the handshake message control"); 
         handshakeDone=true; 
        }else{ 

         System.out.println("server comm receive thread - INSIDE THE WHILE CICLE, before the in.readObject"); 
         File apkReceived = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/testeReceiveServerComm.apk"); 
         byte[] buffer = new byte [4096]; 
         BufferedInputStream bis=new BufferedInputStream(in); 
         FileOutputStream fos=new FileOutputStream(apkReceived); 
         int count=0; 
         int total=0; 
         while((count=bis.read(buffer,0,4096))!=-1){ 

          fos.write(buffer,0,count); 
          total+=count; 
          System.out.println("Server Comm receive thread - already received this ammount : "+total); 

         } 
         ; 
         System.out.println("Already received everything ! "); 
         fos.flush(); 
         bis.close(); 
         fos.close(); 
         System.out.println(" server comm receive thread - already read the object !!!!!!!!!!!!!!"); 

        } 

       } catch (ClassNotFoundException e) { 
        e.printStackTrace(); 
       } 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

沒有理由使用BifferInputStream,因爲您一次只能讀取4092個字節來緩衝自己。您可以嘗試將其提高到8192,但不需要雙緩衝區。 – lionscribe

回答

2

這裏有許多謬誤。同時

  1. 發送設備發送的數據包X,接收器比X分組接受較少

    你不計算數據包,因此你不可能知道。無論如何,收到的'數據包'的數量與TCP中發送的數量無關。重要的是字節的數量,並且沒有證據表明您已經丟失了任何字節。所有你看到的是,當你的緩衝區大小爲4096時,最後一次讀取返回2115字節。這意味着輸入文件的大小是N * 4096 + 2115而不是4096的倍數。

  2. 您正在使用ObjectInputStreamObjectOutputStream,但您只是發送字節。您可以使用套接字自己的輸入和輸出流:無需支付額外的字節流開銷。

  3. 你毫無意義地圍繞the ObjectInputStream`圍繞BufferedInputStream *。它應該是相反的。
  4. 旅遊代碼中的Thread.sleep()實際上是浪費時間。和空間。去掉它。
  5. 在套接字已關閉後您正在刷新輸出流。您應該關閉輸出流,而不是輸入流,並關閉它使刷新冗餘。
  6. 除非你非常幸運,沒有什麼可刷新的,否則你還必須捕捉並忽略由flush()產生的IOException。我不明白這是怎麼可能的,因爲你的文件不是你的緩衝區大小的倍數。
  7. 您正在使用while (!serverSocket.isClosed())作爲從接受的套接字讀取的終止測試。這沒有任何意義。
  8. 您的接收線程都接受並處理單個連接。這使得你的整個服務器是單線程的。應該有一個線程來接受和線程處理每個接受的套接字。

您需要詳細瞭解網絡教程,例如Oracle Java教程的自定義網絡部分。這是寫網絡代碼的方法。

+0

我有那些thread.sleep的,因爲有人告訴我這樣做在stackoverflow。我試過了,但顯然它沒有工作。 7.中的條件就是讓我可以接收多個文件,這樣我總是在聽某些東西。如果我沒有這種情況,服務器如何總是在聽? 此外,我不關閉套接字.. –

+0

服務器將始終監聽單獨的接受線程。你在循環中所做的是從你已經接受的套接字讀取數據。它與「ServerSocket」沒有任何關係。睡在網絡代碼實際上是浪費時間。而你的服務器不會「不停地收聽」。它只處理一個連接。除非你實現上面的(8)。 – EJP

+0

但是如果我實現了這個建議,我應該什麼時候開始接收線程?我無法預測何時我將接收數據,這就是爲什麼我認爲接收事件的線程應始終處於「活動」狀態 –