您遇到的问题与 TCP 流性质有关。
您从服务器发送 100 字节(例如)这一事实并不意味着您在第一次读取时会在客户端读取 100 字节。也许从服务器发送的字节在几个 TCP 段中到达客户端。
您需要实现一个循环,在该循环中阅读直到收到整个消息。让我举一个例子,DataInputStream
而不是BufferedinputStream
。东西很简单,给你举个例子。
假设您事先知道服务器要发送 100 字节的数据。
在客户端中,您需要编写:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
while(!end)
{
int bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length == 100)
{
end = true;
}
}
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
现在,通常事先不知道一个节点(这里的服务器)发送的数据大小。然后您需要定义自己的小协议,用于服务器和客户端(或任何两个节点)之间的通信,使用 TCP 进行通信。
最常见最简单的就是定义TLV:Type、Length、Value。因此,您定义从服务器发送到客户端的每条消息都带有:
- 1 字节指示类型(例如,它也可以是 2 或其他)。
- 消息长度为 1 个字节(或其他)
- 值的 N 个字节(N 表示长度)。
因此,您知道您必须至少接收 2 个字节,并且通过第二个字节,您知道您需要读取多少后续字节。
这只是一个可能的协议的建议。您也可以摆脱“类型”。
所以它会是这样的:
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
int bytesRead = 0;
messageByte[0] = in.readByte();
messageByte[1] = in.readByte();
int bytesToRead = messageByte[1];
while(!end)
{
bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length == bytesToRead )
{
end = true;
}
}
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
以下代码编译并看起来更好。它假定提供长度的前两个字节以二进制格式以网络字节序(大字节序)形式到达。没有关注消息其余部分的不同编码类型。
import java.nio.ByteBuffer;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;
class Test
{
public static void main(String[] args)
{
byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";
try
{
Socket clientSocket;
ServerSocket server;
server = new ServerSocket(30501, 100);
clientSocket = server.accept();
DataInputStream in = new DataInputStream(clientSocket.getInputStream());
int bytesRead = 0;
messageByte[0] = in.readByte();
messageByte[1] = in.readByte();
ByteBuffer byteBuffer = ByteBuffer.wrap(messageByte, 0, 2);
int bytesToRead = byteBuffer.getShort();
System.out.println("About to read " + bytesToRead + " octets");
//The following code shows in detail how to read from a TCP socket
while(!end)
{
bytesRead = in.read(messageByte);
dataString += new String(messageByte, 0, bytesRead);
if (dataString.length() == bytesToRead )
{
end = true;
}
}
//All the code in the loop can be replaced by these two lines
//in.readFully(messageByte, 0, bytesToRead);
//dataString = new String(messageByte, 0, bytesToRead);
System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}