2011-07-13 41 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