DataInputStream readInt()只能运行一次

时间:2013-11-08 12:41:25

标签: java android sockets datainputstream

我正在使用Java套接字使两个Android设备与同一个应用程序进行通信。通信协议是:

1. client sends packet size S
2. client sends byte array with size S

我正在使用DataOutputStreamwriteInt()将大小写为流上的原始值。然后,服务器会读取此值为whit DataInputStreamreadInt()。 问题是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()发送第二个数据包时,服务器会从流中读取错误的大小。

DataOutputStreamDataInputStream以这种方式初始化:

// Server
inputStream = clientSocket.getInputStream();
dataInputStream = new DataInputStream(inputStream);

// Client
outputStream = socket.getOutputStream();
dataOutputStream = new DataOutputStream(outputStream);

我缺少什么?

2 个答案:

答案 0 :(得分:4)

服务器读取尽可能多的数据。它可能读取的内容多于客户端发送的数据包中包含的内容,或者读取的内容可能更少。使用循环时,您似乎处理read返回的内容少于预期的情况,但是当它读取的内容超过数据包中包含的内容时,您也应该处理这种情况。请记住,TCP是面向流的:即使您调用flush,也无法保证远程应用程序在单独调用read时接收数据。

DataInput接口定义了一个名为readFully的方法,它可以根据需要读取完全相同的字节数,不多也不少。这意味着您可以删除循环,简化代码以读取数据包:

packetSize = dataInputStream.readInt();
dataInputStream.readFully(buffer, 0, packetSize);

答案 1 :(得分:1)

在服务器端,您应该在readBytes循环后重新初始化while(true)变量:

while (true) {
     readBytes = 0;
     ....
}

一切顺利。调试器可以帮助您更快地发现此问题。