2

Android での UDP パケット損失の統計情報を提供するアプリケーションを作成しました。これが私のアプリケーションのアーキテクチャです。1) UDP パケットをマルチキャストするアプリケーション。以下はそのコードです。

package rockwell.multicastserverproj;

import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class MainActivity extends AppCompatActivity {

    EditText txtMsg;
    EditText txtPackets;
    EditText txtMs;
    EditText txtBytes;
    EditText txtCount;
    byte[] rtpData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();

            }
        });

        /*Thread thrClient = new Thread(new ReceiveMulticast());
        thrClient.start();*/

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void onBtnClicked(View view)
    {
        Thread threadTotalPackets = new Thread(new SendMulticast());
        threadTotalPackets.start();

        Thread thread = new Thread(new MulticastPackets());
        thread.start();
        //Toast.makeText(this,"Message multicasted",Toast.LENGTH_LONG).show();


    }

    public class MulticastPackets implements Runnable{

        @Override
        public void run() {
            InetAddress group = null;
            MulticastSocket multiSocket = null;
            int PORT = 6500;
            txtPackets =(EditText)findViewById(R.id.txtPackets);
            txtMs = (EditText)findViewById(R.id.txtMs);
            txtBytes = (EditText)findViewById(R.id.txtBytes);
            txtCount = (EditText)findViewById(R.id.txtCount);

            int noOfPackets = Integer.parseInt(txtPackets.getText().toString());
            int delayMS = Integer.parseInt(txtMs.getText().toString());
            int packetSize = Integer.parseInt(txtBytes.getText().toString());
            int cntPacket = Integer.parseInt(txtCount.getText().toString());

            WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
            mLock.acquire();

            try{
                group = InetAddress.getByName("230.0.0.1");
                multiSocket = new MulticastSocket(PORT);
            } catch (IOException e) {
                e.printStackTrace();
            }

            for(int pcktCnt=1; pcktCnt<=noOfPackets; pcktCnt++) {

                rtpData = new byte[packetSize];
                int cnt = unsigned_int(pcktCnt);
                byte[] seqArr = null;
                seqArr = toBytes(cnt);
                byte varFirst = 0xa;
                byte varSecond = 0x5;

                for(int i=4;i<packetSize;i+=2)
                {
                    if(i%4 ==0) {
                        rtpData[i] = varFirst;
                        rtpData[i + 1] = varFirst;
                    }
                    else {
                        rtpData[i] = varSecond;
                        rtpData[i + 1] = varSecond;
                    }
                }

                for(int i=0;i<4;i++)
                {
                    rtpData[i] = seqArr[i];
                }

                DatagramPacket requestPacket = new DatagramPacket(rtpData, rtpData.length, group, PORT);
                try {
                    for(int i=0;i<cntPacket;i++) {
                        multiSocket.send(requestPacket);
                        Thread.sleep(delayMS, 0);
                    }
                    int test = fromByteArray(seqArr);
                    Log.i("Multicast", "Packet send. Sequence number is: " + test);

                } catch (Exception e) {
                    e.printStackTrace();
                }
                int test = fromByteArray(seqArr);
            }

            try{

                multiSocket.leaveGroup(group);
                multiSocket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
            mLock.release();

            MainActivity.this.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this,"Packet sent",Toast.LENGTH_LONG).show();
                }
            });
        }
    }

    public class SendMulticast implements Runnable{
        @Override
        public void run() {
            InetAddress group = null;
            MulticastSocket multiSocket = null;
            int PORT = 5500;
            txtPackets =(EditText)findViewById(R.id.txtPackets);
            txtBytes = (EditText)findViewById(R.id.txtBytes);

            String requestString = txtPackets.getText().toString();
            String strPackSize = txtBytes.getText().toString();

            requestString = requestString +";" + strPackSize;
            Log.i("reqstring",requestString);
            byte[] requestData = new byte[requestString.length()];
            requestData = requestString.getBytes();

            WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
            mLock.acquire();

            try{
                group = InetAddress.getByName("230.0.0.1");
                multiSocket = new MulticastSocket(PORT);
                multiSocket.joinGroup(group);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try{
                DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length, group, PORT);
                multiSocket.send(requestPacket);
                Log.i("multicastproj","message multicasted");

            } catch (IOException e) {
                e.printStackTrace();
            }
            try{
                multiSocket.leaveGroup(group);
                multiSocket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
            mLock.release();
        }
    }

    static int unsigned_int(int nb) {
        if (nb >= 0)
            return (nb);
        else
            return (256 + nb);
    }

    public byte[] toBytes(int i)
    {
        byte[] result = new byte[4];

        result[0] = (byte) (i >> 24);
        result[1] = (byte) (i >> 16);
        result[2] = (byte) (i >> 8);
        result[3] = (byte) (i /*>> 0*/);

        return result;
    }

    public int fromByteArray(byte[] bytes) {
        return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
    }



    public class ReceiveMulticast implements Runnable{
        @Override
        public void run() {
            byte[] requestData = new byte[1024];
            InetAddress group = null;
            MulticastSocket multiSocket = null;
            int PORT = 4500;

            WifiManager wifi = (WifiManager) getSystemService(getApplicationContext().WIFI_SERVICE);
            WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
            mLock.acquire();

            try{
                group = InetAddress.getByName("230.0.0.1");
                multiSocket = new MulticastSocket(PORT);
                multiSocket.joinGroup(group);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try{
                while(true)
                {
                    DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
                    multiSocket.receive(requestPacket);

                    String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
                    Log.d("CreateMulticastServer", "Got request = " + requestString);

                    /*txtMsg = (EditText)findViewById(R.id.txtMsg);
                    txtMsg.setText(requestString);*/
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

            try{
                multiSocket.leaveGroup(group);
                multiSocket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }

            mLock.release();

        }
    }
}

それらのマルチキャスト UDP パケットを受信する別のアプリケーション

継続的に実行され、マルチキャスト パケットを受信するサービス:

package rockwell.packetstatistics;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

/**
 * Created by mmjoshi on 2/10/2016.
 */
public class PacketReceive_Service extends IntentService {
    boolean flag = true;
    int packetSize = 0;
    public PacketReceive_Service() {
        super("PacketReceive_Service");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String strVar = intent.getStringExtra("vari");
        Log.i("onstartservice","string is " + strVar);

        Thread thread = new Thread(new PacketThread());
        thread.setPriority(Thread.MAX_PRIORITY);
        thread.start();

        Thread thread1 = new Thread(new TotalPackets());
        thread1.start();
    }

    public class PacketThread implements Runnable
    {
        @Override
        public void run() {
            InetAddress group = null;
            MulticastSocket multiSocket = null;
            WifiManager.MulticastLock mLock = null;
            int prevSeqNo=0;
            String strMissingPackets="";
            int TotalpacketsReceived = 0;
            try {

                if(packetSize == 0)
                    packetSize = 1036;

                byte[] requestData = new byte[packetSize];
                int PORT = 6500;
                byte varFirst = 0xa;
                byte varSecond = 0x5;

                WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
                mLock = wifi.createMulticastLock("mylock");
                mLock.setReferenceCounted(true);
                mLock.acquire();

                try{
                    group = InetAddress.getByName("230.0.0.1");
                    multiSocket = new MulticastSocket(PORT);
                    multiSocket.joinGroup(group);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                while (flag) {
                    final DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
                    multiSocket.receive(requestPacket);

                    byte[] resultData = requestPacket.getData();

                    byte[] seqArr = new byte[4];
                    for(int i=0;i<4;i++){
                        seqArr[i] = resultData[i];
                    }

                    int seqNo = fromByteArray(seqArr);
                    Log.i("RecvPackets","multiple packet received # is: " + seqNo);
                    if(prevSeqNo!=seqNo)
                    {
                        TotalpacketsReceived++;
                        if(prevSeqNo!=0)
                        {
                            if((seqNo - prevSeqNo)>1)
                            {
                                for(int k=(prevSeqNo+1);k<seqNo;k++)
                                {
                                    strMissingPackets += k + ", ";
                                    sendResultMessage("Missing;" + String.valueOf(k));
                                    Log.i("RecvPackets","Packet missing. Missing# is: " + k);
                                }
                            }
                        }
                        for(int i=4;i<packetSize;i+=2)
                        {
                            if(i%4 ==0) {
                                if(resultData[i] != varFirst ||  resultData[i+1] != varFirst)
                                {
                                    if(seqNo != 1) {
                                        sendResultMessage("DataError;" + String.valueOf(seqNo));
                                        Log.i("DataCheck", "Error in data");
                                    }
                                }
                            }
                            else {
                                if(resultData[i] != varSecond ||  resultData[i+1] != varSecond)
                                {
                                    if(seqNo != 1) {
                                        sendResultMessage("DataError;" + String.valueOf(seqNo));
                                        Log.i("DataCheck", "Error in data");
                                    }
                                }
                            }
                        }
                        prevSeqNo = seqNo;
                        Log.i("MulticastService", "Packet size is: " + packetSize + " Packet receive. Sequence number is: " + seqNo);
                        sendResultMessage("TotalPacketsReceived;" + String.valueOf(TotalpacketsReceived));
                    }
                }


            } catch (IOException e) {
                Log.i("DEU Service", "In cache");
                flag = false;
                e.printStackTrace();
            }
            finally {
                try {
                    if(multiSocket != null) {
                        if(group != null)
                            multiSocket.leaveGroup(group);
                        multiSocket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if(mLock != null)
                    mLock.release();
            }
        }
    }

    private void sendResultMessage(String strPacks) {
        Intent intent = new Intent("intData");
        intent.putExtra("result",strPacks);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
    private void sendTotalPackets(String strPacks) {
        Intent intent = new Intent("intPacket");
        intent.putExtra("result",strPacks);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }
    public int fromByteArray(byte[] bytes) {
        return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
    }

    public class TotalPackets implements Runnable{
        @Override
        public void run() {
            byte[] requestData = new byte[1024];
            InetAddress group = null;
            MulticastSocket multiSocket = null;
            int PORT = 5500;

            WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
            WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
            mLock.acquire();

            try{
                group = InetAddress.getByName("230.0.0.1");
                multiSocket = new MulticastSocket(PORT);
                multiSocket.joinGroup(group);
            } catch (IOException e) {
                e.printStackTrace();
            }

            try{
                while(true)
                {
                    DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
                    multiSocket.receive(requestPacket);

                    String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
                    Log.i("requestString",requestString);
                    String[] spltStr = requestString.split(";");
                    packetSize = Integer.parseInt(spltStr[1].toString());
                    Log.i("service","Packet size is: " + spltStr[1].toString() + " Total Packs: " + spltStr[0]);
                    sendTotalPackets(spltStr[0].toString());
                    /*txtMsg = (EditText)findViewById(R.id.txtMsg);
                    txtMsg.setText(requestString);*/
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

            try{
                multiSocket.leaveGroup(group);
                multiSocket.close();

            } catch (IOException e) {
                e.printStackTrace();
            }

            mLock.release();
        }
    }
}

それで、私の質問は、サービス側でパケットを受信すると、ほとんどの場合、パケットの 5 ~ 7% が失われるということです。つまり、5ms の間隔で 512 バイトの 1000 パケットを送信すると、受信側で 50 ~ 70 パケットの損失が発生します。

このパケット損失を減らす方法はありますか? または、パケット損失を減らすことができるようにコードを改善する可能性はありますか?

前もって感謝します。

4

2 に答える 2

1

あなたができることはあまりありません。

  1. UDP は、配信が保証されないトランスポート層です。

  2. Wi-Fi 経由のパケット損失は、アクセス ポイントのさまざまなメーカー/モデル/構成と、アクセス ポイントが実行されているデバイスによって異なります。

    たとえば、空気の波は通常よりクリーンであるため、5 GHz の方がパフォーマンスが向上する可能性がありますが、2.4 GHz ほど壁を貫通しません。

すべての Android デバイスが同じ Wi-Fi 無線を使用しているわけではありません。

MAC 層でマルチキャストからユニキャストへの変換を行うアクセス ポイントを使用すると、実質的に 0% のパケット損失を得ることができます。したがって、アプリケーション ソフトウェアで UDP を使用します。その後、アクセス ポイントは 802.11 レイヤで内部的に再送信を行います。たとえば、Cisco と Xirrus には、マルチキャストからユニキャストへの変換オプションがあり、実質的に 0% のパケット損失が発生します。ただし、各マルチキャスト ストリームがサブスクライブされた各デバイスに個別に送信されるため、スケーリングがうまくいかないという代償があります。

うーん...ソフトウェアで何ができる....

マルチキャストでのパケット損失に「対処」する方法:

前方誤り訂正。

  • 各パケットを 2 回送信できます。AABBCCDDEE
  • 各パケットを 2 回送信できますが、遅延します。ABACBDCED
  • データの一部を 2 回送信できます。AABCCDE 前方誤り訂正スキームは、より多くの帯域幅をアドバタイズし、遅延も増加させます。

損失隠蔽

  • 損失間のデータを推定することができます。

あなたは実際にあなたのアプリケーションを述べていないので、損失に対処するための提案をすることは困難です. 5ms の制限により、48khz オーディオの 240 フレーム パケットを送信しているように聞こえます。

于 2016-03-22T03:19:15.657 に答える
0

間隔を 5 ミリ秒以上に増やそうとしましたか? また、Wi-Fi の干渉がない場所でこのアプリケーションをテストしようとしましたか?

于 2016-03-17T21:33:46.700 に答える