我正在使用Java套接字使两个Android设备与同一个应用程序通信。通信协议为:
1. client sends packet size S
2. client sends byte array with size S
我正在使用DataOutputStream
和writeInt()
将大小写入流中的原始值。然后,服务器读取此值,DataInputStream
并readInt()
。问题是readInt()
只读取第一个数据包的正确值。此方法第二次返回随机int
。
相关代码片段:
客户端:此方法在与服务器的有效TCP连接之上调用
public void write(byte[] packet)
{
try
{
dataOutputStream.writeInt(packet.length);
dataOutputStream.flush();
dataOutputStream.write(packet);
dataOutputStream.flush();
}
catch (IOException e)
{
Log.e(ERROR_TAG, "write() failed", e);
}
}
服务器端:这是读取数据的循环
...
int readBytes = 0;
int packetSize = 0;
while (true) {
byte[] buffer = new byte[NET_BUFF_SIZE];
try // first it reads the packet size from packet header
{
packetSize = dataInputStream.readInt();
} catch (IOException e) {
Log.e(ERROR_TAG, "readInt() failed", e);
return;
}
while (readBytes < packetSize) {
try {
int readResult = dataInputStream.read(buffer);
if (readResult != -1) {
readBytes += readResult;
} else {
break;
}
} catch (IOException e) {
Log.e(ERROR_TAG, "read() failed", e);
break;
}
}
}
因此,当客户端调用write()
发送第二个数据包时,服务器从流中读取错误的大小。
DataOutputStream
和DataInputStream
按以下方式初始化:
// Server
inputStream = clientSocket.getInputStream();
dataInputStream = new DataInputStream(inputStream);
// Client
outputStream = socket.getOutputStream();
dataOutputStream = new DataOutputStream(outputStream);
我错过了什么?
服务器读取尽可能多的可用数据。它的读取量可能多于客户端发送的数据包中包含的内容,也可能读取的量更少。使用循环,您似乎可以处理read
返回少于预期的情况,但是当它读取的内容超过数据包中包含的内容时,您也应该处理这种情况。请记住,TCP 是面向流的:即使您调用flush
也不能保证远程应用程序在对read
的单独调用中接收数据。
DataInput
接口定义了一个名为 readFully
的方法,该方法可以读取任意数量的字节,不多也不少。这意味着您可以删除循环,从而简化读取数据包的代码:
packetSize = dataInputStream.readInt();
dataInputStream.readFully(buffer, 0, packetSize);
在服务器端,您应该在while(true)
循环后重新初始化 readBytes
变量:
while (true) {
readBytes = 0;
....
}
万事如意。调试器将帮助您更快地发现此问题。