1

Java ソケットを使用して、同じアプリと通信する 2 つの Android デバイスを作成しています。通信プロトコルは次のとおりです。

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

私はDataOutputStreamandwriteInt()を使用して、サイズをストリームの生の値として書き込みます。次に、サーバーはこの値を読み取りDataInputStreamますreadInt()。問題はreadInt()、最初のパケットに対してのみ正しい値を読み取ることです。2 回目は、このメソッドが random を返します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()2 番目のパケットを送信するために呼び出すと、サーバーはストリームから間違ったサイズを読み取ります。

DataOutputStream次のようにDataInputStream初期化されます。

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

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

私は何が欠けていますか?

4

2 に答える 2

4

サーバーは、利用可能な限り多くのデータを読み取ります。クライアントが送信したパケットに含まれているものよりも多く読み取ったり、少なく読み取ったりする場合があります。ループを使用すると、予想よりも少ないリターンが返される場合を処理するように見えますreadが、パケットに含まれているものよりも多くを読み取る場合も処理する必要があります。TCP はストリーム指向であることを忘れないでください。呼び出してもflush、リモート アプリケーションが への個別の呼び出しでデータを受信するという保証はありませんread

このDataInputインターフェースは、readFully正確に必要なだけのバイト数を読み取るメソッドを定義します。これは、ループを削除できることを意味し、コードを簡素化してパケットを次のように読み取ります。

packetSize = dataInputStream.readInt();
dataInputStream.readFully(buffer, 0, packetSize);
于 2013-11-08T12:57:55.113 に答える
1

サーバー側では、ループのreadBytes後に変数を再初期化する必要があります。while(true)

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

ではごきげんよう。デバッガーは、この問題をより早く発見するのに役立ちます。

于 2013-11-08T12:52:20.087 に答える