DataInputStream 的结果不一致
Inconsistent result from DataInputStream
我在 Java 中使用 DataInputStream 和 DataOutputStream 时遇到问题,如果没有一些非常愚蠢的措施我无法解决并且想知道是否有人知道更好的方法(我非常确定有一个,但我没能找到它)。
背景:我希望能够将 Json 字符串发送到服务器并让服务器将该字符串解析为对象。这需要与语言无关,因为我正在研究的项目要求我有一个异构系统。
为了用最简单的示例来说明我的问题,我将排除 Gson/Json 等的创建,因为它可以用任何字符串重新创建。代码如下:
public class ServerSide {
private final int PORT = 5001;
private ServerSocket servSock;
private Socket sock;
private DataInputStream dis;
private DataOutputStream dos;
public ServerSide() throws IOException {
servSock = new ServerSocket(PORT);
}
public void startListening() {
try {
sock = servSock.accept();
dis = new DataInputStream(sock.getInputStream());
byte[] bytes = new byte[1024];
dis.read(bytes);
String receivedMessage = new String(bytes);
System.out.println("Message received: " + receivedMessage);
sock.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
创建 ServerSide() 并稍后调用 startListening(true) 的简单测试 class。
public class ClientSide {
private final int PORT = 5001;
private Socket socket;
private DataOutputStream dos;
public ClientSide() {
}
public void sendMessage(String m) {
try {
socket = new Socket("127.0.0.1", PORT);
dos = new DataOutputStream(socket.getOutputStream());
dos.writeBytes(m);
System.out.println("Message sent: " + m);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
创建 ClientSide() 对象并调用 sendMessage("this is a test message");
的简单测试 class
我遇到的问题是我在服务器端只收到了部分消息。我不确定这是否是输入流或输出流的问题,并且只能通过多次写入和读取数据并修剪两者之间的白色 space 来找到解决方法。我的第一个问题是在尝试将 Json 字符串发送到我用 c# 编写的程序时,它总是发送第一个字符(“{”),然后在下一次读取时发送字符串的其余部分。我通过发送一个 space 然后在服务器端忽略它来解决这个问题。在 java-java 上,当在第一次读取中读取看似随机数量的字符串时,问题变得更糟。
上述服务器端代码的几个示例输出是:
Message received: This is a tes
Message received: T
Message received: T
Message received: T
is.read(bytes);
may return any number of bytes - 从一到 bytes.length
.
Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.
需要重复调用此方法,直到 returns -1
这意味着流结束。
Reading from and Writing to a Socket提供了一个示例,说明如何在面向线路的交换中读取所有数据。对于二进制数据(DataStream 实际生成的数据),您需要结合使用 ByteArrayOutputStream、ByteArrayInputStream 和 DataInputStream:
InputStream sis = sock.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (int len = sis.read(bytes) > 0) {
baos.write(bytes, 0, len);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
DataInputStream dis = new DataInputStream(bais);
byte[] vBytes = new byte[baos.size()];
int sLen = dis.read(vBytes);
String receivedMessage = new String(vBytes, 0, sLen);
System.out.println("Message received: " + receivedMessage);
注意:上面的代码是在回答具体问题。不要将其投入生产:)
感谢@Illya Kysil 提供的帮助,我通过将代码更改为以下内容找到了解决方案:
public class ClientSide {
private final int PORT = 5001;
private Socket socket;
private DataOutputStream dos;
public ClientSide() {
}
public void sendMessage(String m) {
try {
socket = new Socket("127.0.0.1", PORT);
dos = new DataOutputStream(socket.getOutputStream());
byte[] mBytes = m.getBytes();
dos.writeInt(mBytes.length);
dos.write(mBytes);
System.out.println("Message sent: " + m);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
和
public class ServerSide {
private final int PORT = 5001;
private ServerSocket servSock;
private Socket sock;
private DataInputStream dis;
private DataOutputStream dos;
public ServerSide() throws IOException {
servSock = new ServerSocket(PORT);
}
public void startListening() {
try {
sock = servSock.accept();
dis = new DataInputStream(sock.getInputStream());
int length = dis.readInt();
byte[] bytes = new byte[length];
dis.readFully(bytes);
String receivedMessage = new String(bytes);
System.out.println("Message received: " + receivedMessage.trim());
dis.close();
sock.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这将首先发送一个整数,该整数等于正在发送的消息的字节数组的大小。可以在服务器端创建一个这个长度的缓冲区,可以使用 DataInputStream 的 readFully 方法来填充这个缓冲区。
我在 Java 中使用 DataInputStream 和 DataOutputStream 时遇到问题,如果没有一些非常愚蠢的措施我无法解决并且想知道是否有人知道更好的方法(我非常确定有一个,但我没能找到它)。
背景:我希望能够将 Json 字符串发送到服务器并让服务器将该字符串解析为对象。这需要与语言无关,因为我正在研究的项目要求我有一个异构系统。
为了用最简单的示例来说明我的问题,我将排除 Gson/Json 等的创建,因为它可以用任何字符串重新创建。代码如下:
public class ServerSide {
private final int PORT = 5001;
private ServerSocket servSock;
private Socket sock;
private DataInputStream dis;
private DataOutputStream dos;
public ServerSide() throws IOException {
servSock = new ServerSocket(PORT);
}
public void startListening() {
try {
sock = servSock.accept();
dis = new DataInputStream(sock.getInputStream());
byte[] bytes = new byte[1024];
dis.read(bytes);
String receivedMessage = new String(bytes);
System.out.println("Message received: " + receivedMessage);
sock.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
创建 ServerSide() 并稍后调用 startListening(true) 的简单测试 class。
public class ClientSide {
private final int PORT = 5001;
private Socket socket;
private DataOutputStream dos;
public ClientSide() {
}
public void sendMessage(String m) {
try {
socket = new Socket("127.0.0.1", PORT);
dos = new DataOutputStream(socket.getOutputStream());
dos.writeBytes(m);
System.out.println("Message sent: " + m);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
创建 ClientSide() 对象并调用 sendMessage("this is a test message");
的简单测试 class我遇到的问题是我在服务器端只收到了部分消息。我不确定这是否是输入流或输出流的问题,并且只能通过多次写入和读取数据并修剪两者之间的白色 space 来找到解决方法。我的第一个问题是在尝试将 Json 字符串发送到我用 c# 编写的程序时,它总是发送第一个字符(“{”),然后在下一次读取时发送字符串的其余部分。我通过发送一个 space 然后在服务器端忽略它来解决这个问题。在 java-java 上,当在第一次读取中读取看似随机数量的字符串时,问题变得更糟。
上述服务器端代码的几个示例输出是:
Message received: This is a tes
Message received: T
Message received: T
Message received: T
is.read(bytes);
may return any number of bytes - 从一到 bytes.length
.
Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.
需要重复调用此方法,直到 returns -1
这意味着流结束。
Reading from and Writing to a Socket提供了一个示例,说明如何在面向线路的交换中读取所有数据。对于二进制数据(DataStream 实际生成的数据),您需要结合使用 ByteArrayOutputStream、ByteArrayInputStream 和 DataInputStream:
InputStream sis = sock.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (int len = sis.read(bytes) > 0) {
baos.write(bytes, 0, len);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
DataInputStream dis = new DataInputStream(bais);
byte[] vBytes = new byte[baos.size()];
int sLen = dis.read(vBytes);
String receivedMessage = new String(vBytes, 0, sLen);
System.out.println("Message received: " + receivedMessage);
注意:上面的代码是在回答具体问题。不要将其投入生产:)
感谢@Illya Kysil 提供的帮助,我通过将代码更改为以下内容找到了解决方案:
public class ClientSide {
private final int PORT = 5001;
private Socket socket;
private DataOutputStream dos;
public ClientSide() {
}
public void sendMessage(String m) {
try {
socket = new Socket("127.0.0.1", PORT);
dos = new DataOutputStream(socket.getOutputStream());
byte[] mBytes = m.getBytes();
dos.writeInt(mBytes.length);
dos.write(mBytes);
System.out.println("Message sent: " + m);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
和
public class ServerSide {
private final int PORT = 5001;
private ServerSocket servSock;
private Socket sock;
private DataInputStream dis;
private DataOutputStream dos;
public ServerSide() throws IOException {
servSock = new ServerSocket(PORT);
}
public void startListening() {
try {
sock = servSock.accept();
dis = new DataInputStream(sock.getInputStream());
int length = dis.readInt();
byte[] bytes = new byte[length];
dis.readFully(bytes);
String receivedMessage = new String(bytes);
System.out.println("Message received: " + receivedMessage.trim());
dis.close();
sock.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这将首先发送一个整数,该整数等于正在发送的消息的字节数组的大小。可以在服务器端创建一个这个长度的缓冲区,可以使用 DataInputStream 的 readFully 方法来填充这个缓冲区。