4

最近、デバイス間で UDP パケットをブロードキャストする Android (具体的には 2.3.3 および 4.0.4) アプリに UDP パケット シーケンス サポートを実装しました。シーケンス サポートは、基本的に任意の byte[] を受け取り、それを UDP に適したサイズに分割し、UDP パケットとして送信します。UDP シーケンスの識別に役立つヘッダーが含まれています。現在、それを介して大きなデータセットをブロードキャストしているかのように見えます。それをリッスンしているピアは、シーケンスを適切に再構築し、それに応じてデータを処理できます。(カメラで撮影した映像とボイスクリップを配信中)

私が見つけたのは、時折(しばしば)シーケンス内のパケットがドロップされることです。UDP は信頼できないと誰かが言う前に、気にしないでください。私はよく知っています。ここで起こっていることは、必ずしも信頼性が低いというわけではありません。

最初に、UDP パケット シーケンスは 2 秒ごとに 1 つのセグメント化された UDP パケットを送信します。たとえば、データが 128K の場合、3 つのパケットが 6 秒間にわたって送信されます。2 秒の数字は、テストを支援するためのものです。

次に、隔離されたテスト環境には 2 つのデバイスしかありません。それらは、テスト Wi-Fi ネットワーク上の唯一のものです。

第 3 に、これらのデバイスはこれらの UDP パケットの送受信をテストしているだけです。

第 4 に、ログは各パケットの固有のシーケンス ベースの ID を追跡します。これは、送信者がシーケンスで送信したパケットと、受信者が受信したパケットを特定するのに役立ちます。

ログを表示することはできませんが、役に立ちませんが、送信者はすべてのパケットがブロードキャストされたことに気付くでしょうが、受信者はいずれかの時点でパケットをドロップする可能性があります。受信者がすべてを取得する場合もあれば、1 つが欠けている場合もあります。

以上のことをすべて説明しましたが、Android キューは処理ソケットの UDP パケットを受信しましたか?

レシーバーがビジーで UDP パケットを受け入れられないとは思いません。(2 秒ごとに送信されます)

現在、私のサービスは、基本的に DatagramSocket.receive() でループする Runnable を開始し、それに応じて受信したパケットを処理します。

public class MulticastListenerRunnable implements Runnable {
    ...
    public void run() {
        try {
            multicastServer = new DatagramSocket(port, null);
            byte[] buffer = new byte[DatagramSession.DATAGRAM_MAX_SIZE];
            DatagramPacket packet = null;
            byte[] data;

            while(run) {
                try {
                    packet = new DatagramPacket(buffer, buffer.length);
                    packet.setLength(buffer.length);
                    multicastServer.receive(packet);
if(packet.getAddress().getHostAddress().equals("127.0.0.1") || packet.getAddress().getHostAddress().equals(ipAddress)) {
                        continue;
                    }
                    Log.d(TAG, "START PACKET RECEIVE!");
                    processPacket(packet);
            }
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        } catch (Exception e) {             
            Log.e(TAG, e.getMessage());
        }
    }
}

私のログには文字通り次のように表示されます: (これは私のログからのクリップであり、上記のコード クリップの出力から直接ではありません)

03-21 01:26:35.453: D/CommService(6446): START PACKET RECEIVE!
03-21 01:26:35.507: D/CommService(6446): RECEIVED PACKET:  19 of 28 -> 64977(65000 max)
03-21 01:26:35.515: D/CommService(6446): RECEIVED PACKET: This packet isn't alone. More to come!
03-21 01:26:35.515: D/CommService(6446): END PACKET RECEIVE!


03-21 01:26:39.460: D/CommService(6446): START PACKET RECEIVE!
03-21 01:26:39.468: W/DatagramSession(6446): Warning, this packet's sequence isn't in order, last -> 18, new -> 20
03-21 01:26:39.476: D/CommService(6446): RECEIVED PACKET: This packet isn't alone. More to come!
03-21 01:26:39.476: D/CommService(6446): END PACKET RECEIVE!

パケット 20 が欠落していることに注意してください。送信側デバイスのログを見ると、彼がすべてのパケットを 2 秒ごとに送信していることがわかります。パケット 19 が 1:26:35 に受信され、パケット 21 が 1:26:39 に受信されたことがタイム コードでわかります。(間に 4 秒)

私はちょっと途方に暮れています。Android と UDP パケット損失に関する既知の問題はありますか? Android/Java UDP スタック キューは一定期間パケットを受信しましたか?サービスが他のパケットの処理で忙しすぎますか?

TCP への切り替え以外の提案は役に立ちます。前もって感謝します!

4

1 に答える 1

1

わかりました、問題を修正しました。

アプリケーション Service のまっすぐな単一の ScheduledExecutorService + Runnable スレッドを、受信した DatagramPacket を処理するために新しい ExecutorService Runnables を生成する Runnable に切り替えました。受信機に少しの I/O 遅延/ブロッキングがあり、それを別のスレッドに分割してパケット データを処理するとうまくいくようです。新しいアプローチを使用して、デバイス間で 1.8MB サイズのデータ​​ テストを送信しました。

于 2013-09-24T15:14:33.697 に答える