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;
    }
}

我在group address of 225.4.5.6和发送 UDP 多播数据包Port Number 5432

我已经创建了一个类,它将调用一个thread将发送UDP Packets. 另一方面,我制作了一个receiver thread实现Callable 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()。这会导致 a在代码中的可中断InterruptedException位置被抛出,例如在调用时或被 I/O 操作阻塞时。不幸的是,没有实现,所以调用不能被中断。 所以你要么使用而不是,这样就会抛出一个if被调用。或者您需要通过在指定的时间间隔后调用cause来设置超时- 在这种情况下,您不需要中断线程。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);抛出一个。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看起来有点不同;我不确定你打算在那里做什么,因为你在处理列表和数组,但你只有一个未来......所以我假设你想听 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 回答