我在使用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()并在while(true)中调用startListening。
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”);
我遇到的问题是,我在服务器端仅收到部分消息。我不确定这是否是Input或Output流的问题,并且只能通过多次写入和读取数据并修剪两者之间的空格来找到解决方法。我的第一个问题是尝试将Json字符串发送到我用c#编写的程序时,它将始终发送第一个字符(“ {”),然后在下一次读取时发送其余字符串。我通过发送一个空格来解决这个问题,然后在服务器端忽略了这一点。当在第一次读取时读取表面上看似随机的字符串时,问题在Java-java上变得更加严重。
上述代码在服务器端的一些示例输出是:
Message received: This is a tes
Message received: T
Message received: T
Message received: T
答案 0 :(得分:1)
is.read(bytes);
may return any number of bytes-从1到bytes.length
。
从输入流中读取一定数量的字节,并将其存储到缓冲区数组b中。实际读取的字节数以整数形式返回。在输入数据可用,检测到文件末尾或引发异常之前,此方法将一直阻塞。
必须重复调用此方法,直到返回-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);
注意:上面的代码正在回答特定的问题。不要将其投入生产:)
答案 1 :(得分:1)
感谢@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方法填充该缓冲区。