2011-07-13 75 views
0

我正在創建一個服務器/客戶端模型,從服務器向客戶端發送圖像文件。只涉及一個套接字(所有數據都通過它發送)。
服務器首先發送圖像文件的大小,然後通過BufferedOutputStream以字節爲單位發送文件數據。 客戶端首先接收文件大小(大小),創建一個byte [size] imageBytes,然後通過BufferedInputStream將接收到的文件數據寫入imageBytes。PrintWriter vs DataOutputStream,奇怪的行爲

似乎挺直的。當我以不同的方式發送文件大小時會發生問題。

方法1:使用DataOutputStream和DataInputStream發送和接收文件大小爲int。

方式2:使用PrintWriter來打印文件大小,然後刷新;使用BufferedReader來readLine()。

方式1正常工作。但方式2不正確地發送圖像文件。

我不知道這是否因爲BufferedReader在讀取後仍然保持其緩衝區,隨後緩衝區被BuffereInputStream讀取。

這裏是代碼:

服務器:

package test; 

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.DataOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 

public class TestServer { 

    public static void main(String[] args){ 
     try { 
      ServerSocket serverSocket = new ServerSocket(9090); 
      Socket ss = serverSocket.accept(); 
      System.out.println("Client connected!"); 

      File file = new File("ServerFiles/Songs/Covers/album1.jpg"); //Change this path to your own path 
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); 
      byte[] imageBytes = new byte[(int) file.length()]; 
      bis.read(imageBytes); 
      bis.close(); 

      //Way 1------------------------------------------------------------- 
      DataOutputStream dos = new DataOutputStream(ss.getOutputStream()); 
      dos.writeInt((int) file.length()); 
      System.out.println("dos wrote "+file.length()); 
      //End Way 1--------------------------------------------------------- 

      //Way 2------------------------------------------------------------- 
//   PrintWriter pw = new PrintWriter(ss.getOutputStream()); 
//   pw.println(file.length()); 
//   pw.flush(); 
//   System.out.println("pw flushed!"); 
      //End Way 2--------------------------------------------------------- 

      BufferedOutputStream bos = new BufferedOutputStream(ss.getOutputStream()); 
      bos.write(imageBytes); 
      bos.flush(); 
      System.out.println("bos flushed!"); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 

客戶:

package test; 

import java.io.BufferedInputStream; 
import java.io.DataInputStream; 
import java.io.IOException; 
import java.net.InetAddress; 
import java.net.Socket; 
import java.net.UnknownHostException; 
import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

public class TestClient extends JFrame{ 
    Socket cs; 
    ImageIcon imageIcon; 

    public static void main(String[] args){ 
     try { 
      Socket socket = new Socket(InetAddress.getLocalHost(), 9090); 
      new TestClient(socket); 
     } catch (UnknownHostException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

    } 

    public TestClient(Socket cs) throws IOException{ 
     this.cs = cs; 
     init(); 
    } 

    private void init() throws IOException{ 
     imageIcon = getImageIcon(); 
     JLabel jl = new JLabel(imageIcon); 
     JPanel content = (JPanel) this.getContentPane(); 
     content.add(jl); 

     this.setSize(600,400); 
     this.setVisible(true); 
    } 

    private ImageIcon getImageIcon() throws IOException{ 

     //Way 1------------------------------------------------------------- 
     DataInputStream dis = new DataInputStream(cs.getInputStream()); 
     int size = dis.readInt(); 
     System.out.println("size="+size); 
     //End Way 1--------------------------------------------------------- 

     //Way 2------------------------------------------------------------- 
//  BufferedReader br = new BufferedReader(new InputStreamReader(cs.getInputStream())); 
//  int size = Integer.parseInt(br.readLine()); 
//  System.out.println("size="+size); //Print size 
     //End Way 2--------------------------------------------------------- 

     BufferedInputStream bis = new BufferedInputStream(cs.getInputStream()); 
     System.out.println("bis.available()="+bis.available()); //Print bis.available() 
     byte[] imageBytes = new byte[size]; 
     bis.read(imageBytes); 
     return new ImageIcon(imageBytes); 
    } 
} 

輸出:

方法1:

服務器:

Client connected! 
dos wrote 23215 
bos flushed! 

客戶:

size=23215 
bis.available()=23215 

方式2:

服務器:

Client connected! 
pw flushed! 
bos flushed! 

客戶:

size=23215 
bis.available()=6837 

回答

0

我想說的DIF來自DataOutputStream以二進制格式寫入整數,即它將整數分成4個字節並寫入這些字節,而PrintWriter的確是String.valueOf(paramInt),因此會將字符串"23215"的字節發送到客戶端。

既然你已經發送二進制數據(圖像),爲什麼你不堅持1?你通常不需要頭是人類可讀的。

+0

也是行分隔符。 –

0

輸入流沒有合同,表示您將在一次讀取中獲得所有數據。你需要繼續循環可用(),直到它返回一個負數。修改你的代碼來做到這一點,然後再次比較你的兩個場景。

+1

是的,除非不使用available()。 –

+0

正是。 available()返回零不表示傳輸結束。 – EJP

+0

我編輯了我的答案以反映正確的邊界檢查。不確定你的意思是「確切」,如果有另一種方法更適合檢查流結束,請隨時提及它。 – Perception