0

モバイルデバイスから送信UDP Multicastするコードを書いています。Wifiネットワーク内の他のデバイスで実行されているサーバー コードがあります。サーバーはマルチキャストをリッスンし、IP アドレスとシステムのタイプ (タイプ: コンピューター、モバイル デバイス、Raspberry Pi、Flyports など) で応答します。

を送信したモバイル デバイスで、に応答するデバイスのリストUDP Multicastを取得する必要があります。UDP Multicast

このために、 の構造として機能するクラスを作成しましたdevice details

DeviceDetails.class

public class DeviceDetails
{
    String DeviceType;
    String IPAddr;
    public DeviceDetails(String type, String IP)
    {
        this.DeviceType=type;
        this.IPAddr=IP;
    }
}

と で UDP マルチキャスト パケットを送信していgroup address of 225.4.5.6ますPort Number 5432

threadを送信するを呼び出すクラスを作成しましたUDP Packets。一方、応答するデバイスのリストを返すCallablereceiver thread Interface を実装する を作成しました。

コードは次のとおりです。

MulticastReceiver.java

public class MulticastReceiver implements Callable<DeviceDetails>
{
    DatagramSocket socket = null;
    DatagramPacket inPacket = null;
    boolean check = true;
    public MulticastReceiver()
    {
        try
        {
            socket = new DatagramSocket(5500);
        }
        catch(Exception ioe)
        {
            System.out.println(ioe);
        }
    }
    @Override
    public DeviceDetails call() throws Exception
    {
        // TODO Auto-generated method stub
        try
        {
            byte[] inBuf = new byte[WifiConstants.DGRAM_LEN];
            //System.out.println("Listening");
            inPacket = new DatagramPacket(inBuf, inBuf.length);
            if(check)
            {
                socket.receive(inPacket);

            }

            String msg = new String(inBuf, 0, inPacket.getLength());

            Log.v("Received: ","From :" + inPacket.getAddress() + " Msg : " + msg);
            DeviceDetails device = getDeviceFromString(msg);
            Thread.sleep(100);
            return device;
        }
        catch(Exception e)
        {
            Log.v("Receiving Error: ",e.toString());
            return null;
        }
    }
    public DeviceDetails getDeviceFromString(String str)
    {
        String type;
        String IP;
            type=str.substring(0,str.indexOf('`'));
            str = str.substring(str.indexOf('`')+1);
            IP=str;
        DeviceDetails device = new DeviceDetails(type,IP);
        return device;
    }
}

次のコードは、 を呼び出すアクティビティのコードですReceiver Thread

public class DeviceManagerWindow extends Activity
{
    public void searchDevice(View view)
    {
        sendMulticast = new Thread(new MultiCastThread());
        sendMulticast.start();
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        List<Future<DeviceDetails>> deviceList = new ArrayList<Future<DeviceDetails>>();

            Callable<DeviceDetails> device = new MulticastReceiver();
            Future<DeviceDetails> submit = executorService.submit(device);
            deviceList.add(submit);

        DeviceDetails[] devices = new DeviceDetails[deviceList.size()];
        int i=0;
        for(Future<DeviceDetails> future :deviceList)
        {
            try
            {
                devices[i] = future.get();
            }
            catch(Exception e)
            {
                Log.v("future Exception: ",e.toString());
            }
        }
    }
}

現在、パケットを受信する標準的な方法はreceive method、無限ループの下で を呼び出すことです。しかし、着信接続を最初の 30 秒間だけ受信してから、接続の検索を停止したいと考えています。

This is similar to that of a bluetooth searching. It stops after 1 minute of search.

問題は、カウンターを使用できることですが、問題 thread.stop は現在廃止されていることです。 これだけでなく、無限ループの下に置くと、値が返されません。receive method

私は何をすべきか。?たとえば 30 秒間検索してから検索を停止し、応答しているデバイスのリストを返したいとします。

4

2 に答える 2

2

を呼び出す代わりに、 を呼び出すstop()必要がありますinterrupt()。これにより、呼び出し時や I/O 操作によってブロックされたときなど、コードの割り込みInterruptedException可能な場所で aがスローされます。残念ながら、は を実装していないため、 への呼び出しを中断することはできません。そのため、 ifが呼び出された場合にスローされるの代わりに 使用します。または、指定された間隔の後にa をスローするように呼び出してタイムアウトを設定する必要があります。その場合、スレッドを中断する必要はありません。Thread.sleep()DatagramSocketInterruptibleChannelreceive
DatagramChannelDatagramSocketreceive()ClosedByInterruptExceptionThread.interrupt()DatagramSocket.setSoTimeout()receive()SocketTimeoutException

シンプルなアプローチ

最も簡単な方法は、単純にソケット タイムアウトを設定することです。

public MulticastReceiver() {
    try {
        socket = new DatagramSocket(5500);
        socket.setSoTimeout(30 * 1000);
    } catch (Exception ioe) {
        throw new RuntimeException(ioe);
    }
}

これにより、30 秒後にsocket.receive(inPacket);a がスローされます。SocketTimeoutExceptionすでにキャッチExceptionしているので、あとはこれだけです。

MulticastReceiver を割り込み可能にする

これは、より根本的なリファクタリングです。

public class MulticastReceiver implements Callable<DeviceDetails> {
    private DatagramChannel channel;
    public MulticastReceiver() {
        try {
            channel = DatagramChannel.open();
            channel.socket().bind(new InetSocketAddress(5500));
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }
    public DeviceDetails call() throws Exception {
        ByteBuffer inBuf = ByteBuffer.allocate(WifiConstants.DGRAM_LEN);
        SocketAddress socketAddress = channel.receive(inBuf);

        String msg = new String(inBuf.array(), 0, inBuf.capacity());

        Log.v("Received: ","From :" + socketAddress + " Msg : " + msg);
        return getDeviceFromString(msg);;
    }
}

DeviceManagerWindow見た目が少し異なります。リストと配列をいじくり回すので、そこで何をするつもりなのかわかりませんが、未来は1つしかありません...だから、30秒間リッスンして、できるだけ多くのデバイスをフェッチしたいと思います。

ExecutorService executorService = Executors.newFixedThreadPool(1);
MulticastReceiver receiver = new MulticastReceiver();

List<DeviceDetails> devices = new ArrayList<DeviceDetails>();
long runUntil = System.currentTimeMillis() + 30 * 1000;
while (System.currentTimeMillis() < runUntil) {
    Future<Object> future = executorService.submit(receiver);
    try {
        // wait no longer than the original 30s for a result
        long timeout = runUntil - System.currentTimeMillis();
        devices.add(future.get(timeout, TimeUnit.MILLISECONDS));
    } catch (Exception e) {
        Log.v("future Exception: ",e.toString());
    }
}
// shutdown the executor service, interrupting the executed tasks
executorService.shutdownNow();

それはそれについてです。どのソリューションを選択しても、ソケット/チャネルを閉じることを忘れないでください。

于 2013-04-10T08:53:40.353 に答える
-1

私はそれを解決しました..次の方法でコードを実行できます:

DeviceManagerWindow.java

public class DeviceManagerWindow extends Activity
{
    public static Context con;
    public static int rowCounter=0;
    Thread sendMulticast;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_device_manager_window);
        WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
        if(wifi != null)
        {
            WifiManager.MulticastLock lock = wifi.createMulticastLock("WifiDevices");
            lock.acquire();
        }
        TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
        tb.removeAllViews();
        con = getApplicationContext();
    }
    public void searchDevice(View view) throws IOException, InterruptedException
    {
        try
        {
            sendMulticast = new Thread(new MultiCastThread());
            sendMulticast.start();
            sendMulticast.join();
        }
        catch(Exception e)
        {
            Log.v("Exception in Sending:",e.toString());
        }

これが時間制限のある検索です....そして、thread.joinを使用してスレッドを終了できます

        //Device Will only search for 1 minute
        for(long stop=System.nanoTime()+TimeUnit.SECONDS.toNanos(1); stop>System.nanoTime();)
        {
            Thread recv = new Thread(new MulticastReceiver());
            recv.start();
            recv.join();
        }
    }
    public static synchronized void addDevice(DeviceDetails device) throws InterruptedException
    {
        ....
        Prepare your desired list here.
        ....
    }
}

リスニング側にループを追加しないでください。単純に socket.receive を使用する

MulticastReceiver.java

public class MulticastReceiver implements Runnable
{
    DatagramSocket socket = null;
    DatagramPacket inPacket = null;
    public MulticastReceiver()
    {
        try
        {
            socket = new DatagramSocket(WifiConstants.PORT_NO_RECV);
        }
        catch(Exception ioe)
        {
            System.out.println(ioe);
        }
    }
    @Override
    public void run()
    {
        byte[] inBuf = new byte[WifiConstants.DGRAM_LEN];

        //System.out.println("Listening");
        inPacket = new DatagramPacket(inBuf, inBuf.length);
        try
        {
            socket.setSoTimeout(3000)
            socket.receive(inPacket);
            String msg = new String(inBuf, 0, inPacket.getLength());
            Log.v("Received: ","From :" + inPacket.getAddress() + " Msg : " + msg);
            DeviceDetails device = getDeviceFromString(msg);
            DeviceManagerWindow.addDevice(device);

socket.setSoTimeout(3000)ソケットのリッスン時間を 3 秒間だけ設定します。パケットが到着しない場合は、さらに進みます。DeviceManagerWindow.addDevice(device);この行は、呼び出し元のクラスで addDevice メソッドを呼び出します。リストを準備できる場所

        }
        catch(Exception e)
        {
            Log.v("Receiving Error: ",e.toString());
        }
        finally
        {
            socket.close();
        }
    }
    public DeviceDetails getDeviceFromString(String str)
    {
        String type;
        String IP;
            type=str.substring(0,str.indexOf('`'));
            str = str.substring(str.indexOf('`')+1);
            IP=str;
        DeviceDetails device = new DeviceDetails(type,IP);
        return device;
    }
}

うまくいくことを願っています..うまくいくでしょう。ではごきげんよう。問題があればお知らせください。

于 2013-04-10T22:13:33.837 に答える