PrintWriter 与 DataOutputStream,奇怪的行为
我正在创建一个服务器/客户端模型以将图像文件从服务器发送到客户端。仅涉及一个套接字(所有数据都通过它发送)。
服务器首先发送图像文件的大小,然后通过 BufferedOutputStream 以字节为单位发送文件数据。 客户端首先接收到文件的大小(size),创建一个byte[size] imageBytes,然后通过BufferedInputStream将接收到的文件数据写入imageBytes。
看起来很直接。当我以不同方式发送文件大小时,就会出现问题。
方式一:使用DataOutputStream和DataInputStream以int形式发送和接收文件大小。
方式二:使用PrintWriter println(file size),然后flush;使用 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
I'm creating a server/client model to send an image file from the server to the client. There's only ONE socket involved (all data are sent through it).
The server first sends the size of the image file, then sends the file data in bytes through a BufferedOutputStream.
The client first receives the size of the file(size), creates a byte[size] imageBytes, then writes the received file data into imageBytes through a BufferedInputStream.
Seems straight forward. The trouble happens when I send file size in different ways.
Way 1: using DataOutputStream and DataInputStream to send and receive file size as int.
Way 2: using a PrintWriter to println(file size), then flush; using a BufferedReader to readLine().
Way 1 works fine. But Way 2 sends the image file incorrectly.
I wonder if this is because BufferedReader still keeps its buffer after reading, and the buffer is subsequently read by the BuffereInputStream.
Here are the codes:
Server:
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();
}
}
}
Client:
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);
}
}
Outputs:
Way 1:
Server:
Client connected!
dos wrote 23215
bos flushed!
Client:
size=23215
bis.available()=23215
Way 2:
Server:
Client connected!
pw flushed!
bos flushed!
Client:
size=23215
bis.available()=6837
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想说,区别在于
DataOutputStream
以二进制格式写入整数,即将整数拆分为 4 个字节并写入这些字节,而PrintWriter
则执行String .valueOf(paramInt)
,从而将字符串"23215"
的字节发送到客户端。既然您已经发送了二进制数据(图像),为什么不坚持使用方式 1?您通常不需要标题是人类可读的。
I'd say the difference comes from
DataOutputStream
writing the integer in binary format, i.e. it splits the integer into 4 bytes and writes those, whereas thePrintWriter
doesString.valueOf(paramInt)
and thus would send the bytes of the string"23215"
to the client.Since you're already sending binary data (the image), why don't you stick to way 1? You'd normally not need the header to be human readable.
输入流上没有任何合同规定您将在一次读取中获得所有数据。您需要继续循环 available() 直到它返回负数。修改您的代码来执行此操作,然后再次比较您的两个场景。
There is no contract on input streams that say you will get all the data in one read. You need to keep looping on available() until it returns a negative number. Modify your code to do this and then compare your two scenarios again.