2013-10-28 226 views
0

我正在開發客戶端和服務器之間的簡單文件傳輸應用程序。 這裏是我的代碼: 我的客戶(發件人):EOFException或SocketException:在通過套接字傳輸文件時關閉套接字

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){} 
    } 
} 

我想轉院多個文件,所以我不希望關閉套接字。因此,我使用變量「len」來檢查文件是否完全傳輸。

如果我在發送文件之後關閉「輸出」,那麼服務器發出EOFException並且文件發送成功。

當我不關閉輸出時,服務器無法接收文件成功。但是服務器不會拋出EOFException。

你能幫我解決這個問題嗎? 更新:這是我在控制檯屏幕上輸出,如果我不關閉變量 「輸出」 在客戶端:

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(); 

並再次測試。

編輯:用@ Jason的正確評論更新了我的答案。

+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

huhuhuhuhuhuhu,非常感謝你非常非常非常非常非常。 Stackoverflow是greate。 – user1956702

2

問題是,您讀取的文件大小超出文件大小,即讀取的文件大小不是len,而是讀取的文件大小爲bytearray.length

因此,你讀超過len字節,因此len!=currentTot是永遠不會滿足的,因爲,你可以從你的樣本輸出,currentTot == 496len == 246看到。

,讓您的while循環以下變化:

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字節。